@de-otio/epimethian-mcp 4.2.1 → 4.3.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/dist/cli/index.js +72 -16
- package/dist/cli/index.js.map +2 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -30591,6 +30591,26 @@ async function runProfiles() {
|
|
|
30591
30591
|
await setReadOnlyFlag(name, false);
|
|
30592
30592
|
return;
|
|
30593
30593
|
}
|
|
30594
|
+
const disableAttrIdx = args.indexOf("--disable-attribution");
|
|
30595
|
+
if (disableAttrIdx > -1) {
|
|
30596
|
+
const name = args[disableAttrIdx + 1];
|
|
30597
|
+
if (!name || !PROFILE_NAME_RE.test(name)) {
|
|
30598
|
+
console.error("Error: --disable-attribution requires a valid profile name.");
|
|
30599
|
+
process.exit(1);
|
|
30600
|
+
}
|
|
30601
|
+
await setAttributionFlag(name, false);
|
|
30602
|
+
return;
|
|
30603
|
+
}
|
|
30604
|
+
const enableAttrIdx = args.indexOf("--enable-attribution");
|
|
30605
|
+
if (enableAttrIdx > -1) {
|
|
30606
|
+
const name = args[enableAttrIdx + 1];
|
|
30607
|
+
if (!name || !PROFILE_NAME_RE.test(name)) {
|
|
30608
|
+
console.error("Error: --enable-attribution requires a valid profile name.");
|
|
30609
|
+
process.exit(1);
|
|
30610
|
+
}
|
|
30611
|
+
await setAttributionFlag(name, true);
|
|
30612
|
+
return;
|
|
30613
|
+
}
|
|
30594
30614
|
const verbose = args.includes("--verbose");
|
|
30595
30615
|
const profiles = await readProfileRegistry();
|
|
30596
30616
|
if (profiles.length === 0) {
|
|
@@ -30599,19 +30619,20 @@ async function runProfiles() {
|
|
|
30599
30619
|
}
|
|
30600
30620
|
if (verbose) {
|
|
30601
30621
|
console.log(
|
|
30602
|
-
` ${"Profile".padEnd(20)} ${"URL".padEnd(40)} ${"Read-Only".padEnd(12)} Email`
|
|
30622
|
+
` ${"Profile".padEnd(20)} ${"URL".padEnd(40)} ${"Read-Only".padEnd(12)} ${"Attribution".padEnd(14)} Email`
|
|
30603
30623
|
);
|
|
30604
30624
|
console.log(
|
|
30605
|
-
` ${"\u2500".repeat(20)} ${"\u2500".repeat(40)} ${"\u2500".repeat(12)} ${"\u2500".repeat(30)}`
|
|
30625
|
+
` ${"\u2500".repeat(20)} ${"\u2500".repeat(40)} ${"\u2500".repeat(12)} ${"\u2500".repeat(14)} ${"\u2500".repeat(30)}`
|
|
30606
30626
|
);
|
|
30607
30627
|
for (const name of profiles) {
|
|
30608
30628
|
try {
|
|
30609
30629
|
const creds = await readFromKeychain(name);
|
|
30610
30630
|
const settings = await getProfileSettings(name);
|
|
30611
30631
|
const roLabel = settings?.readOnly ? "YES" : "no";
|
|
30632
|
+
const attrLabel = settings?.attribution === false ? "disabled" : "enabled";
|
|
30612
30633
|
if (creds) {
|
|
30613
30634
|
console.log(
|
|
30614
|
-
` ${name.padEnd(20)} ${creds.url.padEnd(40)} ${roLabel.padEnd(12)} ${creds.email}`
|
|
30635
|
+
` ${name.padEnd(20)} ${creds.url.padEnd(40)} ${roLabel.padEnd(12)} ${attrLabel.padEnd(14)} ${creds.email}`
|
|
30615
30636
|
);
|
|
30616
30637
|
} else {
|
|
30617
30638
|
console.log(
|
|
@@ -30629,7 +30650,8 @@ async function runProfiles() {
|
|
|
30629
30650
|
for (const name of profiles) {
|
|
30630
30651
|
const settings = await getProfileSettings(name);
|
|
30631
30652
|
const roSuffix = settings?.readOnly ? " (read-only)" : "";
|
|
30632
|
-
|
|
30653
|
+
const attrSuffix = settings?.attribution === false ? " (no attribution)" : "";
|
|
30654
|
+
console.log(` ${name}${roSuffix}${attrSuffix}`);
|
|
30633
30655
|
}
|
|
30634
30656
|
console.log("\nUse --verbose to show URLs and emails.");
|
|
30635
30657
|
}
|
|
@@ -30645,6 +30667,17 @@ async function setReadOnlyFlag(name, readOnly) {
|
|
|
30645
30667
|
console.log(`Profile "${name}" is now ${label}.`);
|
|
30646
30668
|
console.log("Note: Restart any running MCP servers for this change to take effect.");
|
|
30647
30669
|
}
|
|
30670
|
+
async function setAttributionFlag(name, attribution) {
|
|
30671
|
+
const profiles = await readProfileRegistry();
|
|
30672
|
+
if (!profiles.includes(name)) {
|
|
30673
|
+
console.error(`Error: Profile "${name}" does not exist.`);
|
|
30674
|
+
process.exit(1);
|
|
30675
|
+
}
|
|
30676
|
+
await setProfileSettings(name, { attribution });
|
|
30677
|
+
const label = attribution ? "enabled" : "disabled";
|
|
30678
|
+
console.log(`Attribution footer for profile "${name}" is now ${label}.`);
|
|
30679
|
+
console.log("Note: Restart any running MCP servers for this change to take effect.");
|
|
30680
|
+
}
|
|
30648
30681
|
async function removeProfile(name, force) {
|
|
30649
30682
|
if (!force || import_node_process3.stdin.isTTY) {
|
|
30650
30683
|
if (!import_node_process3.stdin.isTTY) {
|
|
@@ -30749,7 +30782,7 @@ var init_status = __esm({
|
|
|
30749
30782
|
var install_agent_default;
|
|
30750
30783
|
var init_install_agent = __esm({
|
|
30751
30784
|
"install-agent.md"() {
|
|
30752
|
-
install_agent_default = '# Epimethian MCP - Agent Installation Guide\n\n> This document is for AI agents installing and configuring the Epimethian MCP server on behalf of a user.\n\n## Verification\n\nThe official package is **`@de-otio/epimethian-mcp`** (scoped under `@de-otio`).\n\nDo NOT install unscoped alternatives like `epimethian-mcp` \u2014 these are unofficial and potentially unsafe.\n\n## Prerequisites\n\n- Node.js 18 or later\n- npm on PATH\n\n## Step 1: Install\n\n```bash\nnpm install -g @de-otio/epimethian-mcp\n```\n\nVerify the installation:\n\n```bash\nepimethian-mcp --version 2>/dev/null || which epimethian-mcp\n```\n\n## Step 2: Resolve the absolute path\n\nIDE-hosted agents may not resolve PATH correctly. Always use the absolute path in MCP configuration:\n\n```bash\nwhich epimethian-mcp\n```\n\nUse the output as the `command` value in the MCP config below.\n\n## Step 3: Collect configuration\n\nAsk the user for:\n1. **Profile name** \u2014 a short identifier for this Confluence instance (e.g., `jambit`, `acme-corp`). Lowercase alphanumeric and hyphens only.\n2. **Confluence Cloud URL** \u2014 e.g., `https://yoursite.atlassian.net`\n3. **Email address** \u2014 the email associated with their Atlassian account\n\n## Step 4: Write MCP configuration\n\nAdd the server to `.mcp.json` (or the equivalent config file for the user\'s MCP client):\n\n```json\n{\n "mcpServers": {\n "confluence": {\n "command": "<absolute path from Step 2>",\n "env": {\n "CONFLUENCE_PROFILE": "<profile name from Step 3>"\n }\n }\n }\n}\n```\n\n**IMPORTANT:** The only env var needed is `CONFLUENCE_PROFILE`. The URL, email, and API token are stored securely in the OS keychain \u2014 they should NOT appear in config files.\n\n## Step 5: Credential setup\n\nTell the user to run this command in their terminal:\n\n```\nepimethian-mcp setup --profile <profile name from Step 3>\n```\n\nThis interactive command will:\n1. Prompt for the Confluence URL, email, and API token (masked input)\n2. Test the connection\n3. Store all credentials securely in the OS keychain under the named profile\n\nThe API token is generated at: https://id.atlassian.com/manage-profile/security/api-tokens\n\n**Do NOT ask the user for the API token yourself.** The token must go directly from the user into the interactive setup command to avoid appearing in conversation logs.\n\n## Step 6: User must restart the MCP client\n\n**IMPORTANT:** The user must restart their MCP client (e.g., restart Claude Code, reload VS Code, restart Claude Desktop) for the new server configuration to take effect. The MCP client reads `.mcp.json` at startup and does not detect changes while running.\n\nTell the user:\n> Please restart your MCP client now to activate the Confluence tools.\n\n## Step 7: Validation\n\nAfter the user restarts, verify the server is working by listing available Confluence tools or running a simple operation like listing spaces.\n\n## Adding Additional Tenants\n\nTo add a second Confluence instance (e.g., for a different customer):\n\n1. Run `epimethian-mcp setup --profile <new-profile-name>` with the new credentials\n2. In the project that uses the new tenant, update `.mcp.json` to set `CONFLUENCE_PROFILE` to the new profile name\n3. Restart the MCP client\n\nEach VS Code window / Claude Code session uses the profile specified in its `.mcp.json`. Profiles are fully isolated \u2014 different OS keychain entries, different Confluence instances.\n\n## Managing Profiles\n\n- List all profiles: `epimethian-mcp profiles`\n- Show details: `epimethian-mcp profiles --verbose`\n- Check connection: `CONFLUENCE_PROFILE=<name> epimethian-mcp status`\n- Set read-only: `epimethian-mcp profiles --set-read-only <name>`\n- Set read-write: `epimethian-mcp profiles --set-read-write <name>`\n\n### Read-Only Mode\n\nNew profiles default to **read-only**. When read-only, all write tools are blocked and return an error. To enable writes for a profile:\n\n```bash\nepimethian-mcp profiles --set-read-write <name>\n```\n\nOr during setup: `epimethian-mcp setup --profile <name> --read-write`\n\n**Important:** Restart any running MCP servers after changing the read-only flag.\n\n### Removing a Profile\n\nTo delete a profile and its credentials, run:\n\n```bash\nepimethian-mcp profiles --remove <name> --force\n```\n\n**Agents must pass `--force`** because the command normally prompts for interactive confirmation (`Remove profile "<name>" and delete its credentials? [y/N]`), which will fail in non-TTY environments like agent shell sessions. The `--force` flag skips the confirmation prompt when stdin is not a TTY.\n\nThis command:\n1. Deletes the credential entry (URL, email, API token) from the OS keychain\n2. Removes the profile from the registry at `~/.config/epimethian-mcp/profiles.json`\n3. Writes an entry to the audit log at `~/.config/epimethian-mcp/audit.log`\n\nAfter removing a profile, also remove or update any `.mcp.json` files that reference it \u2014 otherwise the MCP server will fail to start with a missing-profile error.\n\n**Errors:**\n- If the profile name is invalid (not matching lowercase alphanumeric/hyphens, 1\u201363 chars), the command exits with code 1\n- If the profile does not exist in the keychain, the keychain deletion is silently skipped \u2014 the registry entry is still removed\n\n## Accessing This Guide Post-Install\n\nOnce installed, this guide is available locally via:\n\n```bash\nepimethian-mcp agent-guide\n```\n\nThis prints the full agent guide to stdout \u2014 no web fetch required.\n\n## Uninstallation\n\nWhen a user asks to uninstall Epimethian MCP, follow these steps:\n\n### Step 1: Check for existing profiles\n\n```bash\nepimethian-mcp profiles\n```\n\n### Step 2: Ask the user about credential cleanup\n\nIf profiles exist, ask the user:\n\n> You have Epimethian profiles configured: [list the profile names]. Would you like to delete all stored credentials before uninstalling? (This removes API tokens from your OS keychain.)\n\n### Step 3: Delete credentials (if the user agrees)\n\nFor each profile the user wants removed:\n\n```bash\nepimethian-mcp profiles --remove <name> --force\n```\n\nOr to remove all profiles:\n\n```bash\nfor name in $(epimethian-mcp profiles | grep \'^ \'); do epimethian-mcp profiles --remove "$name" --force; done\n```\n\n### Step 4: Remove MCP configuration\n\nDelete the `confluence` entry (or the tenant-specific entry like `confluence-jambit`) from the project\'s `.mcp.json`.\n\n### Step 5: Uninstall the package\n\n```bash\nnpm uninstall -g @de-otio/epimethian-mcp\n```\n\n### Step 6: Restart the MCP client\n\nTell the user to restart their MCP client so it stops trying to launch the removed server.\n\n## CI/CD (No Keychain)\n\nFor environments where the OS keychain is unavailable (Docker, CI), set all three env vars directly:\n\n```json\n{\n "mcpServers": {\n "confluence": {\n "command": "<absolute path>",\n "env": {\n "CONFLUENCE_URL": "<url>",\n "CONFLUENCE_EMAIL": "<email>",\n "CONFLUENCE_API_TOKEN": "<token>"\n }\n }\n }\n}\n```\n\n**Warning:** This exposes the API token in the process environment. Use profile-based auth whenever possible.\n\n## Troubleshooting\n\nIf **npm install fails**:\n- Verify Node.js 18+ is installed: `node --version`\n- Verify npm is on PATH: `npm --version`\n- If permission errors occur, the user may need to fix their npm prefix or use a Node version manager (nvm, fnm)\n\nIf **`epimethian-mcp setup` fails**:\n- "Connection failed": Verify the Confluence URL is correct and accessible\n- "Token is invalid or expired": The user needs to generate a new API token at https://id.atlassian.com/manage-profile/security/api-tokens\n- Keychain errors on Linux: The user may need to install `libsecret` / `gnome-keyring` (`apt install libsecret-tools` or equivalent)\n\nIf **the server doesn\'t appear after restart**:\n- Verify the `.mcp.json` path is correct for the user\'s MCP client\n- Verify the `command` value is an absolute path (run `which epimethian-mcp` to confirm)\n- Check that `.mcp.json` contains valid JSON (no trailing commas, correct quoting)\n\n## Available Tools (
|
|
30785
|
+
install_agent_default = '# Epimethian MCP - Agent Installation Guide\n\n> This document is for AI agents installing and configuring the Epimethian MCP server on behalf of a user.\n\n## Verification\n\nThe official package is **`@de-otio/epimethian-mcp`** (scoped under `@de-otio`).\n\nDo NOT install unscoped alternatives like `epimethian-mcp` \u2014 these are unofficial and potentially unsafe.\n\n## Prerequisites\n\n- Node.js 18 or later\n- npm on PATH\n\n## Step 1: Install\n\n```bash\nnpm install -g @de-otio/epimethian-mcp\n```\n\nVerify the installation:\n\n```bash\nepimethian-mcp --version 2>/dev/null || which epimethian-mcp\n```\n\n## Step 2: Resolve the absolute path\n\nIDE-hosted agents may not resolve PATH correctly. Always use the absolute path in MCP configuration:\n\n```bash\nwhich epimethian-mcp\n```\n\nUse the output as the `command` value in the MCP config below.\n\n## Step 3: Collect configuration\n\nAsk the user for:\n1. **Profile name** \u2014 a short identifier for this Confluence instance (e.g., `jambit`, `acme-corp`). Lowercase alphanumeric and hyphens only.\n2. **Confluence Cloud URL** \u2014 e.g., `https://yoursite.atlassian.net`\n3. **Email address** \u2014 the email associated with their Atlassian account\n\n## Step 4: Write MCP configuration\n\nAdd the server to `.mcp.json` (or the equivalent config file for the user\'s MCP client):\n\n```json\n{\n "mcpServers": {\n "confluence": {\n "command": "<absolute path from Step 2>",\n "env": {\n "CONFLUENCE_PROFILE": "<profile name from Step 3>"\n }\n }\n }\n}\n```\n\n**IMPORTANT:** The only env var needed is `CONFLUENCE_PROFILE`. The URL, email, and API token are stored securely in the OS keychain \u2014 they should NOT appear in config files.\n\n## Step 5: Credential setup\n\nTell the user to run this command in their terminal:\n\n```\nepimethian-mcp setup --profile <profile name from Step 3>\n```\n\nThis interactive command will:\n1. Prompt for the Confluence URL, email, and API token (masked input)\n2. Test the connection\n3. Store all credentials securely in the OS keychain under the named profile\n\nThe API token is generated at: https://id.atlassian.com/manage-profile/security/api-tokens\n\n**Do NOT ask the user for the API token yourself.** The token must go directly from the user into the interactive setup command to avoid appearing in conversation logs.\n\n## Step 6: User must restart the MCP client\n\n**IMPORTANT:** The user must restart their MCP client (e.g., restart Claude Code, reload VS Code, restart Claude Desktop) for the new server configuration to take effect. The MCP client reads `.mcp.json` at startup and does not detect changes while running.\n\nTell the user:\n> Please restart your MCP client now to activate the Confluence tools.\n\n## Step 7: Validation\n\nAfter the user restarts, verify the server is working by listing available Confluence tools or running a simple operation like listing spaces.\n\n## Adding Additional Tenants\n\nTo add a second Confluence instance (e.g., for a different customer):\n\n1. Run `epimethian-mcp setup --profile <new-profile-name>` with the new credentials\n2. In the project that uses the new tenant, update `.mcp.json` to set `CONFLUENCE_PROFILE` to the new profile name\n3. Restart the MCP client\n\nEach VS Code window / Claude Code session uses the profile specified in its `.mcp.json`. Profiles are fully isolated \u2014 different OS keychain entries, different Confluence instances.\n\n## Managing Profiles\n\n- List all profiles: `epimethian-mcp profiles`\n- Show details: `epimethian-mcp profiles --verbose`\n- Check connection: `CONFLUENCE_PROFILE=<name> epimethian-mcp status`\n- Set read-only: `epimethian-mcp profiles --set-read-only <name>`\n- Set read-write: `epimethian-mcp profiles --set-read-write <name>`\n\n### Read-Only Mode\n\nNew profiles default to **read-only**. When read-only, all write tools are blocked and return an error. To enable writes for a profile:\n\n```bash\nepimethian-mcp profiles --set-read-write <name>\n```\n\nOr during setup: `epimethian-mcp setup --profile <name> --read-write`\n\n**Important:** Restart any running MCP servers after changing the read-only flag.\n\n### Removing a Profile\n\nTo delete a profile and its credentials, run:\n\n```bash\nepimethian-mcp profiles --remove <name> --force\n```\n\n**Agents must pass `--force`** because the command normally prompts for interactive confirmation (`Remove profile "<name>" and delete its credentials? [y/N]`), which will fail in non-TTY environments like agent shell sessions. The `--force` flag skips the confirmation prompt when stdin is not a TTY.\n\nThis command:\n1. Deletes the credential entry (URL, email, API token) from the OS keychain\n2. Removes the profile from the registry at `~/.config/epimethian-mcp/profiles.json`\n3. Writes an entry to the audit log at `~/.config/epimethian-mcp/audit.log`\n\nAfter removing a profile, also remove or update any `.mcp.json` files that reference it \u2014 otherwise the MCP server will fail to start with a missing-profile error.\n\n**Errors:**\n- If the profile name is invalid (not matching lowercase alphanumeric/hyphens, 1\u201363 chars), the command exits with code 1\n- If the profile does not exist in the keychain, the keychain deletion is silently skipped \u2014 the registry entry is still removed\n\n## Accessing This Guide Post-Install\n\nOnce installed, this guide is available locally via:\n\n```bash\nepimethian-mcp agent-guide\n```\n\nThis prints the full agent guide to stdout \u2014 no web fetch required.\n\n## Uninstallation\n\nWhen a user asks to uninstall Epimethian MCP, follow these steps:\n\n### Step 1: Check for existing profiles\n\n```bash\nepimethian-mcp profiles\n```\n\n### Step 2: Ask the user about credential cleanup\n\nIf profiles exist, ask the user:\n\n> You have Epimethian profiles configured: [list the profile names]. Would you like to delete all stored credentials before uninstalling? (This removes API tokens from your OS keychain.)\n\n### Step 3: Delete credentials (if the user agrees)\n\nFor each profile the user wants removed:\n\n```bash\nepimethian-mcp profiles --remove <name> --force\n```\n\nOr to remove all profiles:\n\n```bash\nfor name in $(epimethian-mcp profiles | grep \'^ \'); do epimethian-mcp profiles --remove "$name" --force; done\n```\n\n### Step 4: Remove MCP configuration\n\nDelete the `confluence` entry (or the tenant-specific entry like `confluence-jambit`) from the project\'s `.mcp.json`.\n\n### Step 5: Uninstall the package\n\n```bash\nnpm uninstall -g @de-otio/epimethian-mcp\n```\n\n### Step 6: Restart the MCP client\n\nTell the user to restart their MCP client so it stops trying to launch the removed server.\n\n## CI/CD (No Keychain)\n\nFor environments where the OS keychain is unavailable (Docker, CI), set all three env vars directly:\n\n```json\n{\n "mcpServers": {\n "confluence": {\n "command": "<absolute path>",\n "env": {\n "CONFLUENCE_URL": "<url>",\n "CONFLUENCE_EMAIL": "<email>",\n "CONFLUENCE_API_TOKEN": "<token>"\n }\n }\n }\n}\n```\n\n**Warning:** This exposes the API token in the process environment. Use profile-based auth whenever possible.\n\n## Troubleshooting\n\nIf **npm install fails**:\n- Verify Node.js 18+ is installed: `node --version`\n- Verify npm is on PATH: `npm --version`\n- If permission errors occur, the user may need to fix their npm prefix or use a Node version manager (nvm, fnm)\n\nIf **`epimethian-mcp setup` fails**:\n- "Connection failed": Verify the Confluence URL is correct and accessible\n- "Token is invalid or expired": The user needs to generate a new API token at https://id.atlassian.com/manage-profile/security/api-tokens\n- Keychain errors on Linux: The user may need to install `libsecret` / `gnome-keyring` (`apt install libsecret-tools` or equivalent)\n\nIf **the server doesn\'t appear after restart**:\n- Verify the `.mcp.json` path is correct for the user\'s MCP client\n- Verify the `command` value is an absolute path (run `which epimethian-mcp` to confirm)\n- Check that `.mcp.json` contains valid JSON (no trailing commas, correct quoting)\n\n## Available Tools (27)\n\n| Tool | Description |\n|------|-------------|\n| `create_page` | Create a new Confluence page |\n| `get_page` | Read a page by ID (use `headings_only` to preview structure first) |\n| `get_page_by_title` | Look up a page by title (use `headings_only` to preview structure first) |\n| `update_page` | Update an existing page |\n| `update_page_section` | Update a single section by heading name |\n| `delete_page` | Delete a page |\n| `list_pages` | List pages in a space |\n| `get_page_children` | Get child pages of a page |\n| `search_pages` | Search pages using CQL (Confluence Query Language) |\n| `get_spaces` | List available Confluence spaces |\n| `add_attachment` | Upload a file attachment to a page |\n| `get_attachments` | List attachments on a page |\n| `add_drawio_diagram` | Add a draw.io diagram to a page |\n| `get_labels` | Get all labels on a Confluence page |\n| `add_label` | Add one or more labels to a Confluence page |\n| `remove_label` | Remove a label from a Confluence page |\n| `get_page_status` | Get the content status badge on a page |\n| `set_page_status` | Set the content status badge on a page |\n| `remove_page_status` | Remove the content status badge from a page |\n| `get_comments` | Get footer and/or inline comments on a page |\n| `create_comment` | Create a footer or inline comment on a page |\n| `resolve_comment` | Resolve or reopen an inline comment |\n| `delete_comment` | Permanently delete a comment |\n| `get_page_versions` | List version history for a page |\n| `get_page_version` | Get page content at a specific historical version |\n| `diff_page_versions` | Compare two versions of a page |\n| `get_version` | Return the epimethian-mcp server version |\n';
|
|
30753
30786
|
}
|
|
30754
30787
|
});
|
|
30755
30788
|
|
|
@@ -45120,12 +45153,14 @@ async function getConfig() {
|
|
|
45120
45153
|
const { url, email: email2, apiToken, profile } = await resolveCredentials();
|
|
45121
45154
|
const registrySettings = profile ? await getProfileSettings(profile) : void 0;
|
|
45122
45155
|
const readOnly = registrySettings?.readOnly === true || process.env.CONFLUENCE_READ_ONLY === "true";
|
|
45156
|
+
const attribution = registrySettings?.attribution !== false && process.env.CONFLUENCE_ATTRIBUTION !== "false";
|
|
45123
45157
|
const authHeader = "Basic " + Buffer.from(`${email2}:${apiToken}`).toString("base64");
|
|
45124
45158
|
_config = Object.freeze({
|
|
45125
45159
|
url,
|
|
45126
45160
|
email: email2,
|
|
45127
45161
|
profile,
|
|
45128
45162
|
readOnly,
|
|
45163
|
+
attribution,
|
|
45129
45164
|
apiV2: `${url}/wiki/api/v2`,
|
|
45130
45165
|
apiV1: `${url}/wiki/rest/api`,
|
|
45131
45166
|
authHeader,
|
|
@@ -45167,8 +45202,9 @@ Expected user: ${email2}
|
|
|
45167
45202
|
}
|
|
45168
45203
|
const profileLabel = profile ? `profile: ${profile}` : "env-var mode";
|
|
45169
45204
|
const readOnlyLabel = config2.readOnly ? ", READ-ONLY" : "";
|
|
45205
|
+
const attributionLabel = config2.attribution ? "" : ", NO-ATTRIBUTION";
|
|
45170
45206
|
console.error(
|
|
45171
|
-
`epimethian-mcp: connected to ${url} as ${email2} (${profileLabel}${readOnlyLabel})`
|
|
45207
|
+
`epimethian-mcp: connected to ${url} as ${email2} (${profileLabel}${readOnlyLabel}${attributionLabel})`
|
|
45172
45208
|
);
|
|
45173
45209
|
}
|
|
45174
45210
|
var PageSchema = external_exports.object({
|
|
@@ -45367,21 +45403,23 @@ async function getPage(pageId, includeBody) {
|
|
|
45367
45403
|
return page;
|
|
45368
45404
|
}
|
|
45369
45405
|
async function createPage(spaceId, title, body, parentId) {
|
|
45406
|
+
const cfg = await getConfig();
|
|
45370
45407
|
const cleanBody = stripAttributionFooter(toStorageFormat(body));
|
|
45408
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("created") : cleanBody;
|
|
45371
45409
|
const payload = {
|
|
45372
45410
|
title,
|
|
45373
45411
|
spaceId,
|
|
45374
45412
|
status: "current",
|
|
45375
45413
|
body: {
|
|
45376
45414
|
representation: "storage",
|
|
45377
|
-
value:
|
|
45415
|
+
value: pageBody
|
|
45378
45416
|
},
|
|
45379
|
-
version: { message:
|
|
45417
|
+
version: { message: `Created by Epimethian v${"4.3.0"}` }
|
|
45380
45418
|
};
|
|
45381
45419
|
if (parentId) payload.parentId = parentId;
|
|
45382
45420
|
const raw = await v2Post("/pages", payload);
|
|
45383
45421
|
const page = PageSchema.parse(raw);
|
|
45384
|
-
pageCache.set(page.id, page.version?.number ?? 1,
|
|
45422
|
+
pageCache.set(page.id, page.version?.number ?? 1, pageBody);
|
|
45385
45423
|
try {
|
|
45386
45424
|
await addLabels(page.id, [ATTRIBUTION_LABEL]);
|
|
45387
45425
|
} catch {
|
|
@@ -45389,8 +45427,9 @@ async function createPage(spaceId, title, body, parentId) {
|
|
|
45389
45427
|
return page;
|
|
45390
45428
|
}
|
|
45391
45429
|
async function updatePage(pageId, opts) {
|
|
45430
|
+
const cfg = await getConfig();
|
|
45392
45431
|
const newVersion = opts.version + 1;
|
|
45393
|
-
const versionMessage = opts.versionMessage ? `${opts.versionMessage} (via Epimethian)` :
|
|
45432
|
+
const versionMessage = opts.versionMessage ? `${opts.versionMessage} (via Epimethian v${"4.3.0"})` : `Updated by Epimethian v${"4.3.0"}`;
|
|
45394
45433
|
const payload = {
|
|
45395
45434
|
id: pageId,
|
|
45396
45435
|
status: "current",
|
|
@@ -45399,9 +45438,10 @@ async function updatePage(pageId, opts) {
|
|
|
45399
45438
|
};
|
|
45400
45439
|
if (opts.body) {
|
|
45401
45440
|
const cleanBody = stripAttributionFooter(toStorageFormat(opts.body));
|
|
45441
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("updated") : cleanBody;
|
|
45402
45442
|
payload.body = {
|
|
45403
45443
|
representation: "storage",
|
|
45404
|
-
value:
|
|
45444
|
+
value: pageBody
|
|
45405
45445
|
};
|
|
45406
45446
|
}
|
|
45407
45447
|
let raw;
|
|
@@ -45415,8 +45455,9 @@ async function updatePage(pageId, opts) {
|
|
|
45415
45455
|
}
|
|
45416
45456
|
const page = PageSchema.parse(raw);
|
|
45417
45457
|
if (opts.body) {
|
|
45418
|
-
const
|
|
45419
|
-
|
|
45458
|
+
const cleanBody = stripAttributionFooter(toStorageFormat(opts.body));
|
|
45459
|
+
const pageBody = cfg.attribution ? cleanBody + "\n" + buildAttributionFooter("updated") : cleanBody;
|
|
45460
|
+
pageCache.set(pageId, newVersion, pageBody);
|
|
45420
45461
|
}
|
|
45421
45462
|
try {
|
|
45422
45463
|
await addLabels(page.id, [ATTRIBUTION_LABEL]);
|
|
@@ -45541,12 +45582,18 @@ var ATTRIBUTION_LABEL = "epimethian-managed";
|
|
|
45541
45582
|
var ATTRIBUTION_START = "<!-- epimethian-attribution-start -->";
|
|
45542
45583
|
var ATTRIBUTION_END = "<!-- epimethian-attribution-end -->";
|
|
45543
45584
|
function buildAttributionFooter(action) {
|
|
45544
|
-
return ATTRIBUTION_START + `<p style="font-size:
|
|
45585
|
+
return ATTRIBUTION_START + `<p style="font-size:9px;color:#999;margin-top:2em;"><em>This page was ${action} with <a href="${GITHUB_URL}">Epimethian</a> v${"4.3.0"}.</em></p>` + ATTRIBUTION_END;
|
|
45545
45586
|
}
|
|
45546
45587
|
function stripAttributionFooter(body) {
|
|
45547
45588
|
return body.replace(
|
|
45548
45589
|
/<!--\s*epimethian-attribution-start\s*-->[\s\S]*?<!--\s*epimethian-attribution-end\s*-->/g,
|
|
45549
45590
|
""
|
|
45591
|
+
).replace(
|
|
45592
|
+
// Also strip bare (unmarked) attribution paragraphs — these appear
|
|
45593
|
+
// when an agent copies page content from get_page and passes it
|
|
45594
|
+
// back to update_page without removing the footer.
|
|
45595
|
+
/<p[^>]*>[\s\S]*?<a\s[^>]*href="https:\/\/github\.com\/de-otio\/epimethian-mcp"[^>]*>Epimethian<\/a>[\s\S]*?<\/p>/gi,
|
|
45596
|
+
""
|
|
45550
45597
|
).trimEnd();
|
|
45551
45598
|
}
|
|
45552
45599
|
async function getLabels(pageId) {
|
|
@@ -46497,7 +46544,8 @@ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
46497
46544
|
"get_page_status",
|
|
46498
46545
|
"get_page_versions",
|
|
46499
46546
|
"get_page_version",
|
|
46500
|
-
"diff_page_versions"
|
|
46547
|
+
"diff_page_versions",
|
|
46548
|
+
"get_version"
|
|
46501
46549
|
]);
|
|
46502
46550
|
function writeGuard(toolName, config2) {
|
|
46503
46551
|
if (!config2.readOnly) return null;
|
|
@@ -47549,6 +47597,14 @@ ${result.diff}${truncNote}` + echo
|
|
|
47549
47597
|
}
|
|
47550
47598
|
}
|
|
47551
47599
|
);
|
|
47600
|
+
server.registerTool(
|
|
47601
|
+
"get_version",
|
|
47602
|
+
{
|
|
47603
|
+
description: "Return the epimethian-mcp server version.",
|
|
47604
|
+
inputSchema: {}
|
|
47605
|
+
},
|
|
47606
|
+
async () => toolResult(`epimethian-mcp v${"4.3.0"}`)
|
|
47607
|
+
);
|
|
47552
47608
|
}
|
|
47553
47609
|
async function main() {
|
|
47554
47610
|
const config2 = await getConfig();
|
|
@@ -47556,7 +47612,7 @@ async function main() {
|
|
|
47556
47612
|
const serverName = config2.profile ? `confluence-${config2.profile}` : "confluence";
|
|
47557
47613
|
const server = new McpServer({
|
|
47558
47614
|
name: serverName,
|
|
47559
|
-
version: "
|
|
47615
|
+
version: "4.3.0"
|
|
47560
47616
|
});
|
|
47561
47617
|
registerTools(server, config2);
|
|
47562
47618
|
const transport = new StdioServerTransport();
|