artsonia-mcp 0.1.0 → 0.2.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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for Artsonia — natural-language access to student-art portfolios, comments, and fans",
10
- "version": "0.1.0"
10
+ "version": "0.2.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "Artsonia",
16
16
  "source": "./",
17
17
  "description": "MCP server for Artsonia — access student portfolios, post comments, and manage fans via natural language",
18
- "version": "0.1.0",
18
+ "version": "0.2.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "artsonia-mcp",
3
3
  "displayName": "Artsonia",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "description": "MCP server for Artsonia — natural-language access to student-art portfolios, comments, and fans",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/dist/bundle.js CHANGED
@@ -32236,7 +32236,7 @@ var VERSION;
32236
32236
  var init_version = __esm({
32237
32237
  "src/version.ts"() {
32238
32238
  "use strict";
32239
- VERSION = "0.1.0";
32239
+ VERSION = "0.2.0";
32240
32240
  }
32241
32241
  });
32242
32242
 
@@ -38724,12 +38724,14 @@ function parseProfileForm(html) {
38724
38724
  if (!form) throw new Error("Could not find the Artsonia profile form (#TheForm).");
38725
38725
  const fields = {};
38726
38726
  const checkboxes = {};
38727
+ const checkboxValues = {};
38727
38728
  for (const el of form.querySelectorAll("input, select")) {
38728
38729
  const name = el.getAttribute("name");
38729
38730
  if (!name) continue;
38730
38731
  const type = el.getAttribute("type") ?? el.tagName.toLowerCase();
38731
38732
  if (type === "checkbox") {
38732
38733
  checkboxes[name] = el.hasAttribute("checked");
38734
+ checkboxValues[name] = el.getAttribute("value") ?? "Y";
38733
38735
  } else if (el.tagName.toLowerCase() === "select") {
38734
38736
  const sel = el.querySelector("option[selected]") ?? el.querySelector("option");
38735
38737
  fields[name] = sel?.getAttribute("value") ?? "";
@@ -38737,7 +38739,7 @@ function parseProfileForm(html) {
38737
38739
  fields[name] = el.getAttribute("value") ?? "";
38738
38740
  }
38739
38741
  }
38740
- return { fields, checkboxes };
38742
+ return { fields, checkboxes, checkboxValues };
38741
38743
  }
38742
38744
  function registerWriteTools(server, client2) {
38743
38745
  server.registerTool(
@@ -38813,7 +38815,7 @@ function registerWriteTools(server, client2) {
38813
38815
  if (news === void 0 && artist_activity === void 0 && promos === void 0) {
38814
38816
  return textResult({ error: "Specify at least one of news / artist_activity / promos." });
38815
38817
  }
38816
- const { fields, checkboxes } = parseProfileForm(await client2.fetchHtml("/members/profile/"));
38818
+ const { fields, checkboxes, checkboxValues } = parseProfileForm(await client2.fetchHtml("/members/profile/"));
38817
38819
  const nextChecks = { ...checkboxes };
38818
38820
  for (const [key, fieldName] of Object.entries(OPTIN_FIELDS)) {
38819
38821
  const want = desired[key];
@@ -38825,14 +38827,10 @@ function registerWriteTools(server, client2) {
38825
38827
  params.set(name, "");
38826
38828
  continue;
38827
38829
  }
38828
- if (name === "DidChangePassword") {
38829
- params.set(name, "0");
38830
- continue;
38831
- }
38832
38830
  params.set(name, value);
38833
38831
  }
38834
38832
  for (const [name, on] of Object.entries(nextChecks)) {
38835
- if (on) params.set(name, "on");
38833
+ if (on) params.set(name, checkboxValues[name] ?? "Y");
38836
38834
  }
38837
38835
  const resultingOptIns = {
38838
38836
  OptInNews: nextChecks["OptInNews"] ?? false,
@@ -18,6 +18,7 @@ export function parseProfileForm(html) {
18
18
  throw new Error('Could not find the Artsonia profile form (#TheForm).');
19
19
  const fields = {};
20
20
  const checkboxes = {};
21
+ const checkboxValues = {};
21
22
  for (const el of form.querySelectorAll('input, select')) {
22
23
  const name = el.getAttribute('name');
23
24
  if (!name)
@@ -25,6 +26,9 @@ export function parseProfileForm(html) {
25
26
  const type = (el.getAttribute('type') ?? el.tagName.toLowerCase());
26
27
  if (type === 'checkbox') {
27
28
  checkboxes[name] = el.hasAttribute('checked');
29
+ // Artsonia opt-in checkboxes submit value="Y" when checked — a literal "on"
30
+ // is silently ignored by the server (the save 302s but persists nothing).
31
+ checkboxValues[name] = el.getAttribute('value') ?? 'Y';
28
32
  }
29
33
  else if (el.tagName.toLowerCase() === 'select') {
30
34
  const sel = el.querySelector('option[selected]') ?? el.querySelector('option');
@@ -34,7 +38,7 @@ export function parseProfileForm(html) {
34
38
  fields[name] = el.getAttribute('value') ?? '';
35
39
  }
36
40
  }
37
- return { fields, checkboxes };
41
+ return { fields, checkboxes, checkboxValues };
38
42
  }
39
43
  export function registerWriteTools(server, client) {
40
44
  server.registerTool('artsonia_post_comment', {
@@ -101,7 +105,7 @@ export function registerWriteTools(server, client) {
101
105
  if (news === undefined && artist_activity === undefined && promos === undefined) {
102
106
  return textResult({ error: 'Specify at least one of news / artist_activity / promos.' });
103
107
  }
104
- const { fields, checkboxes } = parseProfileForm(await client.fetchHtml('/members/profile/'));
108
+ const { fields, checkboxes, checkboxValues } = parseProfileForm(await client.fetchHtml('/members/profile/'));
105
109
  const nextChecks = { ...checkboxes };
106
110
  for (const [key, fieldName] of Object.entries(OPTIN_FIELDS)) {
107
111
  const want = desired[key];
@@ -109,20 +113,21 @@ export function registerWriteTools(server, client) {
109
113
  nextChecks[fieldName] = want;
110
114
  }
111
115
  const params = new URLSearchParams();
116
+ // Re-send every non-checkbox field verbatim (preserving the form's own
117
+ // DidChangePassword="N" so the server doesn't attempt a password change),
118
+ // except the password fields, which are always blanked.
112
119
  for (const [name, value] of Object.entries(fields)) {
113
120
  if (PASSWORD_FIELDS.has(name)) {
114
121
  params.set(name, '');
115
122
  continue;
116
123
  }
117
- if (name === 'DidChangePassword') {
118
- params.set(name, '0');
119
- continue;
120
- }
121
124
  params.set(name, value);
122
125
  }
126
+ // Checked opt-ins are submitted with the checkbox's real value ("Y"); unchecked
127
+ // boxes are omitted, exactly as the browser form does.
123
128
  for (const [name, on] of Object.entries(nextChecks)) {
124
129
  if (on)
125
- params.set(name, 'on');
130
+ params.set(name, checkboxValues[name] ?? 'Y');
126
131
  }
127
132
  const resultingOptIns = {
128
133
  OptInNews: nextChecks['OptInNews'] ?? false,
@@ -1,3 +1,3 @@
1
1
  // Single source of truth for the server version. The marker is what
2
2
  // release-please bumps; versionSyncTest asserts it equals package.json.
3
- export const VERSION = '0.1.0'; // x-release-please-version
3
+ export const VERSION = '0.2.0'; // x-release-please-version
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "artsonia-mcp",
5
5
  "display_name": "Artsonia",
6
- "version": "0.1.0",
6
+ "version": "0.2.0",
7
7
  "description": "Artsonia student-art portfolios, comments, and fans for Claude — access via natural language",
8
8
  "author": {
9
9
  "name": "Chris Chall",
package/package.json CHANGED
@@ -1,16 +1,39 @@
1
1
  {
2
2
  "name": "artsonia-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "mcpName": "io.github.chrischall/artsonia-mcp",
5
5
  "description": "Artsonia MCP server for Claude — developed and maintained by AI (Claude Code)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
7
- "repository": { "type": "git", "url": "git+https://github.com/chrischall/artsonia-mcp.git" },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/chrischall/artsonia-mcp.git"
10
+ },
8
11
  "license": "MIT",
9
- "keywords": ["mcp", "model-context-protocol", "claude", "ai", "artsonia", "student-art", "portfolio", "parent"],
12
+ "keywords": [
13
+ "mcp",
14
+ "model-context-protocol",
15
+ "claude",
16
+ "ai",
17
+ "artsonia",
18
+ "student-art",
19
+ "portfolio",
20
+ "parent"
21
+ ],
10
22
  "type": "module",
11
- "engines": { "node": ">=18.14" },
12
- "bin": { "artsonia-mcp": "dist/index.js" },
13
- "files": ["dist", ".claude-plugin", "skills", ".mcp.json", "server.json", "manifest.json"],
23
+ "engines": {
24
+ "node": ">=18.14"
25
+ },
26
+ "bin": {
27
+ "artsonia-mcp": "dist/index.js"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ ".claude-plugin",
32
+ "skills",
33
+ ".mcp.json",
34
+ "server.json",
35
+ "manifest.json"
36
+ ],
14
37
  "scripts": {
15
38
  "build": "tsc && npm run bundle",
16
39
  "bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --external:dotenv --external:@fetchproxy/server --outfile=dist/bundle.js",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/artsonia-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.1.0",
9
+ "version": "0.2.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "artsonia-mcp",
14
- "version": "0.1.0",
14
+ "version": "0.2.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },