@simplysf/simply-atlassian-mcp 0.4.1 → 0.5.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/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  [![NPM](https://img.shields.io/npm/v/@simplysf/simply-atlassian-mcp?label=@simplysf/simply-atlassian-mcp)](https://npmjs.com/@simplysf/simply-atlassian-mcp) [![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://raw.githubusercontent.com/SimplySF/simply-atlassian/main/LICENSE.txt)
4
4
 
5
5
  A [Model Context Protocol](https://modelcontextprotocol.io/) server that gives an AI agent in
6
- Claude Desktop, Claude Code, Cursor, VS Code, or any other MCP client the same Jira and Confluence
7
- capabilities as the [`@simplysf/simply-atlassian`](../simply-atlassian) CLI: one tool per command,
6
+ Claude Desktop, Claude Code, Cursor, Gemini, VS Code, or any other MCP client the same Jira and
7
+ Confluence capabilities as the [`@simplysf/simply-atlassian`](../simply-atlassian) CLI: one tool per command,
8
8
  calling the same [`@simplysf/simply-atlassian-core`](../simply-atlassian-core) library in-process.
9
9
  The agent gets the CLI's credential handling, `dryRun` previews, read-only guard, credential
10
10
  redaction, and error messages, and the same raw JSON the CLI prints with `--json`, without a
@@ -21,10 +21,20 @@ the [documentation site](https://simplysf.github.io/simply-atlassian/guides/mcp-
21
21
  The server needs Node.js 22 or later.
22
22
 
23
23
  ```bash
24
- npm install -g @simplysf/simply-atlassian-mcp
25
- simply-atlassian-mcp --help
24
+ npm install -g @simplysf/simply-cli
25
+ simply atlassian mcp --list
26
26
  ```
27
27
 
28
+ `--list` prints every tool this server would register, then exits. Run without it and the server
29
+ waits on stdin for a client, which at a terminal looks like a hang.
30
+
31
+ The plugin installs itself the first time you run the command, so `@simplysf/simply-cli` is the
32
+ only thing to install.
33
+
34
+ **The standalone binary still works.** `npm install -g @simplysf/simply-atlassian-mcp` and
35
+ `simply-atlassian-mcp` are unchanged, and an existing client configuration pointing at them keeps
36
+ running.
37
+
28
38
  `--help` prints the options and every tool the server can register, so it doubles as a check that
29
39
  the install worked. It prints to stderr, because stdout is reserved for the protocol stream.
30
40
 
@@ -109,6 +119,83 @@ servers and whether each one connected.
109
119
  Cursor reads `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for every project, with
110
120
  the same `mcpServers` shape as Claude Desktop.
111
121
 
122
+ ### Gemini CLI
123
+
124
+ Gemini CLI reads `~/.gemini/settings.json` for every project, or `.gemini/settings.json` inside a
125
+ project, with the same `mcpServers` shape as Claude Desktop:
126
+
127
+ ```json
128
+ {
129
+ "mcpServers": {
130
+ "simply-atlassian": {
131
+ "command": "simply-atlassian-mcp",
132
+ "args": ["--env-file", "/home/me/atlassian.env"]
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ `gemini mcp add` writes the same entry. `--scope user` puts it in the global file; the default
139
+ `project` scope writes `.gemini/settings.json`, and `-e` sets one variable on the entry:
140
+
141
+ ```sh
142
+ gemini mcp add --scope user \
143
+ -e JIRA_URL=https://your-site.atlassian.net \
144
+ -e JIRA_USERNAME=you@example.com \
145
+ -e JIRA_API_TOKEN=... \
146
+ simply-atlassian simply-atlassian-mcp
147
+ ```
148
+
149
+ Flags meant for the server itself, `--env-file` and `--allow-writes`, are easier to add by editing
150
+ `settings.json`, because `gemini mcp add` reads a leading-dash argument as one of its own options.
151
+
152
+ Values in `env` expand `$NAME` from the environment Gemini started in, which keeps the token out of
153
+ the settings file without an env file:
154
+
155
+ ```json
156
+ {
157
+ "mcpServers": {
158
+ "simply-atlassian": {
159
+ "command": "npx",
160
+ "args": ["-y", "@simplysf/simply-atlassian-mcp"],
161
+ "env": {
162
+ "JIRA_URL": "https://your-site.atlassian.net",
163
+ "JIRA_USERNAME": "you@example.com",
164
+ "JIRA_API_TOKEN": "$JIRA_API_TOKEN"
165
+ }
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ Two other fields on an entry matter here. `trust: true` bypasses the per-call confirmation for
172
+ every tool on that server, so leave it off on any entry started with `--allow-writes` and let a
173
+ person approve each write. `includeTools` and `excludeTools` narrow what the model is shown, which
174
+ is a second way to express the split in [Let the agent write](#let-the-agent-write): a write entry
175
+ can register the write tools while holding back the destructive ones.
176
+
177
+ ```json
178
+ {
179
+ "mcpServers": {
180
+ "simply-atlassian-write": {
181
+ "command": "simply-atlassian-mcp",
182
+ "args": ["--allow-writes", "--env-file", "/home/me/atlassian-write.env"],
183
+ "excludeTools": ["jira_issue_delete", "jira_issue_comment_delete", "confluence_page_delete"],
184
+ "trust": false
185
+ }
186
+ }
187
+ }
188
+ ```
189
+
190
+ Inside a session, `/mcp` lists the configured servers, whether each connected, and the tools it
191
+ registered.
192
+
193
+ ### Gemini Code Assist
194
+
195
+ Agent mode in the VS Code extension reads that same `~/.gemini/settings.json`, so an entry added
196
+ for Gemini CLI is already in place. In IntelliJ the file is `mcp.json` in the IDE's configuration
197
+ directory, holding the same `mcpServers` object.
198
+
112
199
  ### VS Code
113
200
 
114
201
  VS Code reads `.vscode/mcp.json`, with a `servers` key and an explicit transport type:
@@ -0,0 +1,28 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Serves this package's MCP tools over stdio, as a command of the `simply` CLI.
4
+ *
5
+ * The same server the `simply-atlassian-mcp` binary runs — that binary still exists and still works.
6
+ * This exists so an MCP client can be pointed at `simply` with no separate global install: the
7
+ * plugin is fetched on first use like any other.
8
+ *
9
+ * **Extends `Command` directly, not `AtlassianCommand`.** That is deliberate and load-bearing. stdout
10
+ * is the protocol channel here, and the shared base class enables oclif's `--json` flag, which
11
+ * makes oclif print this command's return value to stdout when it is passed. One stray object on
12
+ * that stream corrupts the session, and the client's error would say nothing about why.
13
+ */
14
+ export default class AtlassianMcp extends Command {
15
+ static enableJsonFlag: boolean;
16
+ static readonly summary = "Serve the Atlassian MCP tools over stdio.";
17
+ static readonly description: string;
18
+ static readonly examples: {
19
+ description: string;
20
+ command: string;
21
+ }[];
22
+ static readonly flags: {
23
+ 'allow-writes': import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
+ 'env-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
+ list: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ };
27
+ run(): Promise<void>;
28
+ }
@@ -0,0 +1,94 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { Command, Flags } from '@oclif/core';
17
+ import { selectTools, startServer } from '../../index.js';
18
+ /**
19
+ * Serves this package's MCP tools over stdio, as a command of the `simply` CLI.
20
+ *
21
+ * The same server the `simply-atlassian-mcp` binary runs — that binary still exists and still works.
22
+ * This exists so an MCP client can be pointed at `simply` with no separate global install: the
23
+ * plugin is fetched on first use like any other.
24
+ *
25
+ * **Extends `Command` directly, not `AtlassianCommand`.** That is deliberate and load-bearing. stdout
26
+ * is the protocol channel here, and the shared base class enables oclif's `--json` flag, which
27
+ * makes oclif print this command's return value to stdout when it is passed. One stray object on
28
+ * that stream corrupts the session, and the client's error would say nothing about why.
29
+ */
30
+ export default class AtlassianMcp extends Command {
31
+ // Explicitly off, restating the class comment as code so a later refactor onto a base class
32
+ // that enables it fails loudly here rather than silently corrupting a protocol stream.
33
+ static enableJsonFlag = false;
34
+ static summary = 'Serve the Atlassian MCP tools over stdio.';
35
+ static description = 'Runs a Model Context Protocol server exposing Jira and Confluence as tools, for Claude Desktop, Claude ' +
36
+ 'Code, Cursor, Gemini CLI, VS Code, or any other MCP client. It speaks the protocol on stdout, ' +
37
+ 'so it is meant to be launched by a client rather than run by hand — at a terminal it will ' +
38
+ 'simply appear to hang, waiting for a client that is not there.\n\n' +
39
+ 'Point a client at it with "command": "simply", "args": ["atlassian", "mcp"]. The plugin installs ' +
40
+ 'itself on first use, so nothing needs installing beyond the simply CLI.\n\n' +
41
+ 'Only read tools are registered unless --allow-writes is passed, and ATLASSIAN_READ_ONLY still ' +
42
+ 'refuses every write even then.';
43
+ static examples = [
44
+ {
45
+ description: 'Register only the read tools, taking settings from the environment',
46
+ command: '<%= config.bin %> <%= command.id %>',
47
+ },
48
+ {
49
+ description: 'Allow writes, with settings from a file',
50
+ command: '<%= config.bin %> <%= command.id %> --allow-writes --env-file ~/atlassian.env',
51
+ },
52
+ {
53
+ description: 'List the tools this server would register, without starting it',
54
+ command: '<%= config.bin %> <%= command.id %> --list',
55
+ },
56
+ ];
57
+ static flags = {
58
+ 'allow-writes': Flags.boolean({
59
+ summary: 'Also register the tools that change data.',
60
+ description: 'Off by default, so a server launched without thinking about it can only read. ' +
61
+ 'ATLASSIAN_READ_ONLY in the environment still refuses every write even when this is on.',
62
+ default: false,
63
+ }),
64
+ 'env-file': Flags.string({
65
+ char: 'e',
66
+ summary: 'Path to a .env file holding connection settings.',
67
+ description: 'Use an absolute path. MCP clients launch a server from a working directory of their own, ' +
68
+ 'so ~ and relative paths may not resolve.',
69
+ }),
70
+ list: Flags.boolean({
71
+ summary: 'Print the tools that would be registered, then exit without serving.',
72
+ description: 'Printed to stderr, because stdout belongs to the protocol.',
73
+ default: false,
74
+ }),
75
+ };
76
+ async run() {
77
+ const { flags } = await this.parse(AtlassianMcp);
78
+ if (flags.list) {
79
+ // stderr, like every other diagnostic here: a client that inspects stdout must only ever
80
+ // find protocol traffic on it.
81
+ const tools = selectTools(flags['allow-writes']);
82
+ process.stderr.write([
83
+ `${tools.length} tool(s) would be registered${flags['allow-writes'] ? ' (writes allowed)' : ' (read-only)'}:`,
84
+ ...tools.map((tool) => ` ${tool.name.padEnd(28)} ${tool.title}`),
85
+ '',
86
+ ].join('\n'));
87
+ return;
88
+ }
89
+ // Resolves once the transport is connected; the process then stays alive until the client
90
+ // closes the stream, which is why this command never returns in normal use.
91
+ await startServer({ allowWrites: flags['allow-writes'], envFile: flags['env-file'] });
92
+ }
93
+ }
94
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/commands/atlassian/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,OAAO;IAC/C,4FAA4F;IAC5F,uFAAuF;IAChF,MAAM,CAAU,cAAc,GAAG,KAAK,CAAC;IAEvC,MAAM,CAAmB,OAAO,GAAG,2CAA2C,CAAC;IAC/E,MAAM,CAAmB,WAAW,GACzC,yGAAyG;QACzG,gGAAgG;QAChG,4FAA4F;QAC5F,oEAAoE;QACpE,mGAAmG;QACnG,6EAA6E;QAC7E,gGAAgG;QAChG,gCAAgC,CAAC;IAE5B,MAAM,CAAmB,QAAQ,GAAG;QACzC;YACE,WAAW,EAAE,oEAAoE;YACjF,OAAO,EAAE,qCAAqC;SAC/C;QACD;YACE,WAAW,EAAE,yCAAyC;YACtD,OAAO,EAAE,+EAA+E;SACzF;QACD;YACE,WAAW,EAAE,gEAAgE;YAC7E,OAAO,EAAE,4CAA4C;SACtD;KACF,CAAC;IAEK,MAAM,CAAmB,KAAK,GAAG;QACtC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC;YAC5B,OAAO,EAAE,2CAA2C;YACpD,WAAW,EACT,gFAAgF;gBAChF,wFAAwF;YAC1F,OAAO,EAAE,KAAK;SACf,CAAC;QACF,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,GAAG;YACT,OAAO,EAAE,kDAAkD;YAC3D,WAAW,EACT,2FAA2F;gBAC3F,0CAA0C;SAC7C,CAAC;QACF,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,OAAO,EAAE,sEAAsE;YAC/E,WAAW,EAAE,4DAA4D;YACzE,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAEjD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,yFAAyF;YACzF,+BAA+B;YAC/B,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;YACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;gBACE,GAAG,KAAK,CAAC,MAAM,+BAA+B,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,cAAc,GAAG;gBAC7G,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjE,EAAE;aACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;YACF,OAAO;QACT,CAAC;QAED,0FAA0F;QAC1F,4EAA4E;QAC5E,MAAM,WAAW,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC"}
@@ -0,0 +1,65 @@
1
+ {
2
+ "commands": {
3
+ "atlassian:mcp": {
4
+ "aliases": [],
5
+ "args": {},
6
+ "description": "Runs a Model Context Protocol server exposing Jira and Confluence as tools, for Claude Desktop, Claude Code, Cursor, Gemini CLI, VS Code, or any other MCP client. It speaks the protocol on stdout, so it is meant to be launched by a client rather than run by hand — at a terminal it will simply appear to hang, waiting for a client that is not there.\n\nPoint a client at it with \"command\": \"simply\", \"args\": [\"atlassian\", \"mcp\"]. The plugin installs itself on first use, so nothing needs installing beyond the simply CLI.\n\nOnly read tools are registered unless --allow-writes is passed, and ATLASSIAN_READ_ONLY still refuses every write even then.",
7
+ "examples": [
8
+ {
9
+ "description": "Register only the read tools, taking settings from the environment",
10
+ "command": "<%= config.bin %> <%= command.id %>"
11
+ },
12
+ {
13
+ "description": "Allow writes, with settings from a file",
14
+ "command": "<%= config.bin %> <%= command.id %> --allow-writes --env-file ~/atlassian.env"
15
+ },
16
+ {
17
+ "description": "List the tools this server would register, without starting it",
18
+ "command": "<%= config.bin %> <%= command.id %> --list"
19
+ }
20
+ ],
21
+ "flags": {
22
+ "allow-writes": {
23
+ "description": "Off by default, so a server launched without thinking about it can only read. ATLASSIAN_READ_ONLY in the environment still refuses every write even when this is on.",
24
+ "name": "allow-writes",
25
+ "summary": "Also register the tools that change data.",
26
+ "allowNo": false,
27
+ "type": "boolean"
28
+ },
29
+ "env-file": {
30
+ "char": "e",
31
+ "description": "Use an absolute path. MCP clients launch a server from a working directory of their own, so ~ and relative paths may not resolve.",
32
+ "name": "env-file",
33
+ "summary": "Path to a .env file holding connection settings.",
34
+ "hasDynamicHelp": false,
35
+ "multiple": false,
36
+ "type": "option"
37
+ },
38
+ "list": {
39
+ "description": "Printed to stderr, because stdout belongs to the protocol.",
40
+ "name": "list",
41
+ "summary": "Print the tools that would be registered, then exit without serving.",
42
+ "allowNo": false,
43
+ "type": "boolean"
44
+ }
45
+ },
46
+ "hasDynamicHelp": false,
47
+ "hiddenAliases": [],
48
+ "id": "atlassian:mcp",
49
+ "pluginAlias": "@simplysf/simply-atlassian-mcp",
50
+ "pluginName": "@simplysf/simply-atlassian-mcp",
51
+ "pluginType": "core",
52
+ "strict": true,
53
+ "summary": "Serve the Atlassian MCP tools over stdio.",
54
+ "enableJsonFlag": false,
55
+ "isESM": true,
56
+ "relativePath": [
57
+ "lib",
58
+ "commands",
59
+ "atlassian",
60
+ "mcp.js"
61
+ ]
62
+ }
63
+ },
64
+ "version": "0.5.0"
65
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@simplysf/simply-atlassian-mcp",
3
3
  "description": "Model Context Protocol server exposing Jira and Confluence to AI agents, built on @simplysf/simply-atlassian-core",
4
- "version": "0.4.1",
4
+ "version": "0.5.0",
5
5
  "author": "@ClayChipps",
6
6
  "homepage": "https://github.com/SimplySF/simply-atlassian",
7
7
  "bugs": "https://github.com/SimplySF/simply-atlassian/issues",
@@ -14,7 +14,8 @@
14
14
  "node": ">=22.0.0"
15
15
  },
16
16
  "files": [
17
- "/lib"
17
+ "/lib",
18
+ "/oclif.manifest.json"
18
19
  ],
19
20
  "keywords": [
20
21
  "mcp",
@@ -33,11 +34,14 @@
33
34
  },
34
35
  "dependencies": {
35
36
  "@modelcontextprotocol/sdk": "^1.30.0",
37
+ "@oclif/core": "^4.11.2",
36
38
  "@simplysf/simply-atlassian-core": "^0.5.0",
37
39
  "zod": "^4.5.4"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@vitest/coverage-v8": "^4.1.10",
43
+ "oclif": "^4.23.0",
44
+ "shx": "^0.4.0",
41
45
  "vitest": "^4.1.10"
42
46
  },
43
47
  "publishConfig": {
@@ -49,6 +53,8 @@
49
53
  "fix-license": "eslint src test --fix --rule \"header/header: [2]\"",
50
54
  "format": "wireit",
51
55
  "lint": "wireit",
56
+ "postpack": "shx rm -f oclif.manifest.json",
57
+ "prepack": "pnpm run compile && oclif manifest",
52
58
  "test": "wireit",
53
59
  "test:coverage": "wireit",
54
60
  "test:only": "wireit",
@@ -167,5 +173,15 @@
167
173
  "service": true
168
174
  }
169
175
  },
170
- "gitHead": "b0d86a9014b4e6483898577781f4090a20685b70"
176
+ "oclif": {
177
+ "bin": "simply",
178
+ "commands": "./lib/commands",
179
+ "topicSeparator": " ",
180
+ "topics": {
181
+ "atlassian": {
182
+ "description": "Work with Atlassian products."
183
+ }
184
+ }
185
+ },
186
+ "gitHead": "5dae9b6f994f73ca5b6ba14644d80f34fa520cbe"
171
187
  }