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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +6 -8
- package/dist/src/tools/writes.js +12 -7
- package/dist/src/version.js +1 -1
- package/manifest.json +1 -1
- package/package.json +29 -6
- package/server.json +2 -2
|
@@ -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.
|
|
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.
|
|
18
|
+
"version": "0.2.0",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
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.
|
|
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, "
|
|
38833
|
+
if (on) params.set(name, checkboxValues[name] ?? "Y");
|
|
38836
38834
|
}
|
|
38837
38835
|
const resultingOptIns = {
|
|
38838
38836
|
OptInNews: nextChecks["OptInNews"] ?? false,
|
package/dist/src/tools/writes.js
CHANGED
|
@@ -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, '
|
|
130
|
+
params.set(name, checkboxValues[name] ?? 'Y');
|
|
126
131
|
}
|
|
127
132
|
const resultingOptIns = {
|
|
128
133
|
OptInNews: nextChecks['OptInNews'] ?? false,
|
package/dist/src/version.js
CHANGED
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.
|
|
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.
|
|
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": {
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/chrischall/artsonia-mcp.git"
|
|
10
|
+
},
|
|
8
11
|
"license": "MIT",
|
|
9
|
-
"keywords": [
|
|
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": {
|
|
12
|
-
|
|
13
|
-
|
|
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.
|
|
9
|
+
"version": "0.2.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "artsonia-mcp",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.2.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|