note-connector 0.2.4 → 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 +61 -7
- 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
package/dist/paths.js
CHANGED
|
@@ -40,6 +40,10 @@ export function resolveNoteConnectorRepo() {
|
|
|
40
40
|
if (fs.existsSync(path.join(fromGlobal, "src", "note_mcp"))) {
|
|
41
41
|
return fromGlobal;
|
|
42
42
|
}
|
|
43
|
+
const fromBundled = path.resolve(here, "..", "py");
|
|
44
|
+
if (fs.existsSync(path.join(fromBundled, "src", "note_mcp"))) {
|
|
45
|
+
return fromBundled;
|
|
46
|
+
}
|
|
43
47
|
throw new Error("note-connector Python 本体が見つかりません。\n"
|
|
44
48
|
+ " note-connector config set repoPath /path/to/note-connector\n"
|
|
45
49
|
+ "または NOTE_CONNECTOR_REPO=/path/to/note-connector を設定してください。\n"
|
|
@@ -39,15 +39,52 @@ function ensureUv() {
|
|
|
39
39
|
function repoHasPython(root) {
|
|
40
40
|
return fs.existsSync(path.join(root, "pyproject.toml")) && fs.existsSync(path.join(root, "src", "note_mcp"));
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
42
|
+
function npmPackagePythonRoot() {
|
|
43
|
+
try {
|
|
44
|
+
const root = resolveNoteConnectorRepo();
|
|
45
|
+
return root;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function copyBundledPython(target) {
|
|
52
|
+
const source = npmPackagePythonRoot();
|
|
53
|
+
if (!source) {
|
|
54
|
+
throw new Error("npm パッケージにPythonソースが見つかりません。npm install -g を再実行してください。");
|
|
55
|
+
}
|
|
56
|
+
// Remove old repo and copy fresh from npm package
|
|
57
|
+
if (fs.existsSync(target)) {
|
|
58
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
59
|
+
}
|
|
44
60
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
45
|
-
|
|
61
|
+
console.log("Python ソースを npm からコピー中…");
|
|
62
|
+
fs.cpSync(source, target, { recursive: true });
|
|
46
63
|
}
|
|
47
|
-
function updateRepo(
|
|
64
|
+
function updateRepo(target) {
|
|
65
|
+
// Prefer bundled npm copy over git pull
|
|
66
|
+
const npmRoot = npmPackagePythonRoot();
|
|
67
|
+
if (npmRoot && target !== npmRoot) {
|
|
68
|
+
try {
|
|
69
|
+
// Check which is newer: npm package vs local repo
|
|
70
|
+
const npmSrcStat = fs.statSync(path.join(npmRoot, "src", "note_mcp", "server.py"));
|
|
71
|
+
const localSrcStat = fs.statSync(path.join(target, "src", "note_mcp", "server.py"));
|
|
72
|
+
if (npmSrcStat.mtimeMs > localSrcStat.mtimeMs) {
|
|
73
|
+
copyBundledPython(target);
|
|
74
|
+
console.log("note-connector を最新に更新しました(npm同梱版)");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// File stat failed, skip update
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Fall back to git pull for manually cloned repos
|
|
83
|
+
if (!commandExists("git"))
|
|
84
|
+
return;
|
|
48
85
|
try {
|
|
49
86
|
const result = spawnSync("git", ["pull", "--ff-only", "origin", "main"], {
|
|
50
|
-
cwd:
|
|
87
|
+
cwd: target,
|
|
51
88
|
encoding: "utf8",
|
|
52
89
|
timeout: 15000,
|
|
53
90
|
});
|
|
@@ -72,9 +109,23 @@ function ensureRepoPath(config) {
|
|
|
72
109
|
const target = path.join(configDir(), "repo");
|
|
73
110
|
if (!repoHasPython(target)) {
|
|
74
111
|
if (fs.existsSync(target)) {
|
|
75
|
-
|
|
112
|
+
// Incomplete, remove and retry
|
|
113
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
// Try to copy from npm package first, fall back to git clone
|
|
116
|
+
const npmRoot = npmPackagePythonRoot();
|
|
117
|
+
if (npmRoot) {
|
|
118
|
+
copyBundledPython(target);
|
|
119
|
+
}
|
|
120
|
+
else if (commandExists("git")) {
|
|
121
|
+
console.log(`Cloning note-connector → ${target}`);
|
|
122
|
+
execFileSync("git", ["clone", "--depth", "1", DEFAULT_REPO, target], { stdio: "inherit" });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new Error("Python ソースが見つからず、git もありません。\n" +
|
|
126
|
+
"npm install -g note-connector を再実行するか、\n" +
|
|
127
|
+
"git clone でリポジトリを取得して repoPath を設定してください。");
|
|
76
128
|
}
|
|
77
|
-
cloneRepo(target);
|
|
78
129
|
}
|
|
79
130
|
const updated = { ...config, repoPath: target };
|
|
80
131
|
saveConfig(updated);
|
|
@@ -111,6 +162,9 @@ export async function setupDependencies() {
|
|
|
111
162
|
if (!commandExists("tailscale") && config.tunnel.provider === "tailscale" && !config.tunnel.publicUrl) {
|
|
112
163
|
warnings.push("Tailscale CLI がありません。tunnel.publicUrl を設定するか Tailscale をインストールしてください。");
|
|
113
164
|
}
|
|
165
|
+
if (!commandExists("git")) {
|
|
166
|
+
warnings.push("git がありません。最新バージョンは npm install -g note-connector で更新されます。");
|
|
167
|
+
}
|
|
114
168
|
return {
|
|
115
169
|
uvInstalled: true,
|
|
116
170
|
repoReady: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "note-connector",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist/**",
|
|
15
|
+
"py/**",
|
|
15
16
|
"README.md"
|
|
16
17
|
],
|
|
17
18
|
"engines": {
|
|
18
19
|
"node": ">=20.10"
|
|
19
20
|
},
|
|
20
21
|
"scripts": {
|
|
21
|
-
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"build": "tsc -p tsconfig.json && mkdir -p py && cp -r ../src ../pyproject.toml py/ && find py -name __pycache__ -type d -exec rm -rf {} + 2>/dev/null; true",
|
|
22
23
|
"test": "npm run build && node --test dist/net.test.js dist/version.test.js dist/config.test.js",
|
|
23
24
|
"prepublishOnly": "npm run build"
|
|
24
25
|
},
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "note-connector"
|
|
3
|
+
version = "0.2.6"
|
|
4
|
+
description = "note-connector: MCP server and ChatGPT connector for note.com"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
keywords = ["mcp", "note.com", "blog", "automation"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 4 - Beta",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"fastmcp>=2.0.0",
|
|
18
|
+
"playwright>=1.40.0",
|
|
19
|
+
"keyring>=25.0.0",
|
|
20
|
+
"httpx>=0.27.0",
|
|
21
|
+
"markdown-it-py>=3.0.0",
|
|
22
|
+
"pydantic>=2.0.0",
|
|
23
|
+
"pyyaml>=6.0.0",
|
|
24
|
+
"uvicorn>=0.40.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[dependency-groups]
|
|
28
|
+
dev = [
|
|
29
|
+
"beautifulsoup4>=4.12.0",
|
|
30
|
+
"mitmproxy>=11.0.2",
|
|
31
|
+
"mypy>=1.19.1",
|
|
32
|
+
"pytest>=8.4.1",
|
|
33
|
+
"pytest-asyncio>=0.23.0",
|
|
34
|
+
"ruff>=0.12.4",
|
|
35
|
+
"types-beautifulsoup4>=4.12.0",
|
|
36
|
+
"types-pyyaml>=6.0.0",
|
|
37
|
+
]
|
|
38
|
+
docs = [
|
|
39
|
+
"myst-parser>=4.0.1",
|
|
40
|
+
"sphinx>=8.2.3",
|
|
41
|
+
"sphinx-rtd-theme>=3.0.2",
|
|
42
|
+
"sphinxcontrib-mermaid>=1.1.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["hatchling"]
|
|
47
|
+
build-backend = "hatchling.build"
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.wheel]
|
|
50
|
+
packages = ["src/note_mcp"]
|
|
51
|
+
|
|
52
|
+
[tool.ruff]
|
|
53
|
+
line-length = 120
|
|
54
|
+
target-version = "py313"
|
|
55
|
+
exclude = ["tests/manual"]
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM"]
|
|
59
|
+
ignore = []
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint.isort]
|
|
62
|
+
known-first-party = ["note_mcp"]
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.13"
|
|
66
|
+
strict = true
|
|
67
|
+
warn_return_any = true
|
|
68
|
+
warn_unused_ignores = true
|
|
69
|
+
disallow_untyped_defs = true
|
|
70
|
+
exclude = ["^debug/", "^tests/manual/"]
|
|
71
|
+
|
|
72
|
+
[[tool.mypy.overrides]]
|
|
73
|
+
module = "mitmproxy.*"
|
|
74
|
+
ignore_errors = true
|
|
75
|
+
follow_imports = "skip"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
asyncio_mode = "auto"
|
|
80
|
+
testpaths = ["tests"]
|
|
81
|
+
markers = [
|
|
82
|
+
"requires_auth: tests requiring real authentication",
|
|
83
|
+
"e2e: end-to-end tests",
|
|
84
|
+
"docker: tests requiring Docker environment with browser/proxy",
|
|
85
|
+
"playwright: tests requiring Playwright browser automation",
|
|
86
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Entry point for note-mcp MCP server.
|
|
2
|
+
|
|
3
|
+
Run with: uv run python -m note_mcp
|
|
4
|
+
Or via fastmcp: uv run fastmcp run note_mcp.server:mcp
|
|
5
|
+
|
|
6
|
+
Investigator mode (stdio):
|
|
7
|
+
uv run python -m note_mcp --investigator
|
|
8
|
+
Or set INVESTIGATOR_MODE=1 environment variable
|
|
9
|
+
|
|
10
|
+
Investigator mode (HTTP for remote access):
|
|
11
|
+
uv run python -m note_mcp --investigator --http --port 9000
|
|
12
|
+
This exposes MCP tools via HTTP transport for Claude Code on host.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main() -> None:
|
|
22
|
+
"""Run the MCP server."""
|
|
23
|
+
parser = argparse.ArgumentParser(description="note-mcp MCP server")
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--investigator",
|
|
26
|
+
action="store_true",
|
|
27
|
+
help="Enable investigator mode for API investigation",
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--http",
|
|
31
|
+
action="store_true",
|
|
32
|
+
help="Use HTTP transport instead of stdio (for remote access)",
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--host",
|
|
36
|
+
type=str,
|
|
37
|
+
default="0.0.0.0",
|
|
38
|
+
help="Host to bind HTTP server (default: 0.0.0.0)",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--port",
|
|
42
|
+
type=int,
|
|
43
|
+
default=9000,
|
|
44
|
+
help="Port for HTTP transport (default: 9000)",
|
|
45
|
+
)
|
|
46
|
+
args = parser.parse_args()
|
|
47
|
+
|
|
48
|
+
if args.investigator:
|
|
49
|
+
os.environ["INVESTIGATOR_MODE"] = "1"
|
|
50
|
+
|
|
51
|
+
# Import server after setting environment variable
|
|
52
|
+
from note_mcp.server import mcp
|
|
53
|
+
|
|
54
|
+
if args.http:
|
|
55
|
+
# stateless_http=True to avoid session ID management issues
|
|
56
|
+
# when the server is restarted (e.g., container restart).
|
|
57
|
+
# Application-level session state (CaptureSessionManager) is
|
|
58
|
+
# independent of HTTP transport session management.
|
|
59
|
+
mcp.run(transport="http", host=args.host, port=args.port, stateless_http=True)
|
|
60
|
+
else:
|
|
61
|
+
mcp.run()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
main()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""API module for note-mcp.
|
|
2
|
+
|
|
3
|
+
Provides HTTP client and API operations for note.com.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from note_mcp.api.articles import (
|
|
7
|
+
create_draft,
|
|
8
|
+
delete_all_drafts,
|
|
9
|
+
delete_article,
|
|
10
|
+
delete_draft,
|
|
11
|
+
list_articles,
|
|
12
|
+
publish_article,
|
|
13
|
+
unpublish_article,
|
|
14
|
+
update_article,
|
|
15
|
+
)
|
|
16
|
+
from note_mcp.api.client import NoteAPIClient
|
|
17
|
+
from note_mcp.api.images import upload_body_image, upload_eyecatch_image
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"NoteAPIClient",
|
|
21
|
+
"create_draft",
|
|
22
|
+
"delete_all_drafts",
|
|
23
|
+
"delete_article",
|
|
24
|
+
"delete_draft",
|
|
25
|
+
"list_articles",
|
|
26
|
+
"publish_article",
|
|
27
|
+
"unpublish_article",
|
|
28
|
+
"update_article",
|
|
29
|
+
"upload_body_image",
|
|
30
|
+
"upload_eyecatch_image",
|
|
31
|
+
]
|