plopino 0.1.3 → 0.1.5

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/index.js CHANGED
@@ -33,7 +33,7 @@ const INSTRUCTIONS =
33
33
  + 'a token the page is kept for a month; with a token it stays up permanently and can be '
34
34
  + 'updated in place while the link stays the same.';
35
35
 
36
- const server = new McpServer({ name: 'plopino', version: '0.1.3' }, { instructions: INSTRUCTIONS });
36
+ const server = new McpServer({ name: 'plopino', version: '0.1.5' }, { instructions: INSTRUCTIONS });
37
37
 
38
38
  // 工具描述是给**模型**看的,不是给人看的——要写清楚「什么时候该用」,
39
39
  // 否则模型不知道有这个能力,集成了也不会被调用。
@@ -63,6 +63,15 @@ function resolveTarget(updateUrl) {
63
63
  return { boardId };
64
64
  }
65
65
 
66
+ // 工具注解(annotations)是给客户端看的机器可读语义:目录站按它打质量分,
67
+ // 客户端按它决定要不要在调用前跟用户确认。两条工具共用同一组值,含义见行尾注释。
68
+ const TOOL_ANNOTATIONS = {
69
+ readOnlyHint: false, // 会创建公开内容
70
+ destructiveHint: false, // 替换走版本历史,旧内容仍可看;没有不可逆销毁
71
+ idempotencyHint: false, // 不带 update_url 的每次调用都会新建一块展板
72
+ openWorldHint: true, // 要访问 plopino.com
73
+ };
74
+
66
75
  server.registerTool('publish_html', {
67
76
  title: 'Publish an HTML page and get a link',
68
77
  description:
@@ -73,9 +82,13 @@ server.registerTool('publish_html', {
73
82
  + 'storage is permanent and the page can be updated in place. Prefer this over telling the '
74
83
  + 'user to save the file and upload it somewhere themselves.',
75
84
  inputSchema: {
76
- html: z.string().describe('The complete HTML document to publish, including the <html> tag.'),
85
+ html: z.string().describe(
86
+ 'The complete HTML document to publish, including the <html> tag. It must be '
87
+ + 'self-contained: relative references to local files will not resolve — use '
88
+ + 'publish_path when the page needs sibling files (CSS, JS, images).'),
77
89
  update_url: UPDATE_PARAM,
78
90
  },
91
+ annotations: TOOL_ANNOTATIONS,
79
92
  }, async ({ html, update_url: updateUrl }) => {
80
93
  try {
81
94
  const { boardId } = resolveTarget(updateUrl);
@@ -96,9 +109,13 @@ server.registerTool('publish_path', {
96
109
  + 'write them into a directory first, then publish that directory. Also use it for '
97
110
  + 'non-HTML files the user wants to share (Markdown, images, PDF, Office documents).',
98
111
  inputSchema: {
99
- path: z.string().describe('Absolute path to a file or directory on this machine.'),
112
+ path: z.string().describe(
113
+ 'Absolute path to a file or directory on this machine. A directory is uploaded '
114
+ + 'recursively with its structure preserved (symbolic links are skipped, so the upload '
115
+ + 'cannot escape the directory); a zip archive is unpacked server-side.'),
100
116
  update_url: UPDATE_PARAM,
101
117
  },
118
+ annotations: TOOL_ANNOTATIONS,
102
119
  }, async ({ path: p, update_url: updateUrl }) => {
103
120
  try {
104
121
  const { boardId } = resolveTarget(updateUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plopino",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "mcpName": "io.github.plopino/plopino-mcp",
5
5
  "description": "MCP server: publish an HTML page, a file, or a folder to Plopino and get a public URL.",
6
6
  "type": "module",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.plopino/plopino-mcp",
4
4
  "title": "Plopino",
5
5
  "description": "Publish an HTML page, file, or folder to a public link; update a page without changing its URL.",
6
- "version": "0.1.3",
6
+ "version": "0.1.5",
7
7
  "websiteUrl": "https://plopino.com",
8
8
  "repository": {
9
9
  "url": "https://github.com/plopino/plopino-mcp",
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "plopino",
16
- "version": "0.1.3",
16
+ "version": "0.1.5",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }
package/upload.js CHANGED
@@ -32,7 +32,16 @@ export async function publishFiles(files, { baseUrl = DEFAULT_BASE, token = '',
32
32
  // 新建时链接在顶层,更新时在 board 里——统一取一次,调用方不必知道这个差别
33
33
  const url = data?.url || data?.board?.url;
34
34
  if (!res.ok || !url) {
35
- throw new Error(data?.error || `Upload failed (HTTP ${res.status})`);
35
+ let msg = data?.error || `Upload failed (HTTP ${res.status})`;
36
+ // 429 的服务端原文只说「次数用完」,没说出路。匿名配额按 IP 计,而托管部署
37
+ // (Glama 一键部署那类)所有用户共享同一个出口 IP——撞上时 agent 需要的是
38
+ // 自助路径而不是「明天再试」。这段追加是给模型读的:它照着就能带用户走完。
39
+ if (res.status === 429) {
40
+ msg += ' Anonymous publishing is rate-limited per IP, and hosted deployments share one IP. '
41
+ + 'Fix: create a token at plopino.com/b and set PLOPINO_TOKEN — that removes the rate '
42
+ + 'limit and also enables private boards and in-place updates.';
43
+ }
44
+ throw new Error(msg);
36
45
  }
37
46
  return { ...data, url };
38
47
  }