paput-mcp 2.4.0 → 2.6.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 +46 -5
- package/dist/check-http.js +27 -0
- package/dist/check-http.js.map +1 -0
- package/dist/cli/index.js +29 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/login.js +235 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/logout.js +65 -0
- package/dist/cli/logout.js.map +1 -0
- package/dist/handlers/create-memo/handler.js +3 -23
- package/dist/handlers/create-memo/handler.js.map +1 -1
- package/dist/handlers/memo-projects.js +29 -0
- package/dist/handlers/memo-projects.js.map +1 -0
- package/dist/handlers/update-memo/handler.js +3 -23
- package/dist/handlers/update-memo/handler.js.map +1 -1
- package/dist/http.js +153 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/schemas/tool-input.js +16 -0
- package/dist/schemas/tool-input.js.map +1 -1
- package/dist/server.js +22 -20
- package/dist/server.js.map +1 -1
- package/dist/services/api/client.js +8 -3
- package/dist/services/api/client.js.map +1 -1
- package/dist/services/oauth/local-auth.js +128 -0
- package/dist/services/oauth/local-auth.js.map +1 -0
- package/dist/tool.js +21 -7
- package/dist/tool.js.map +1 -1
- package/docs/directory-submission.md +102 -0
- package/docs/privacy-policy.md +61 -0
- package/docs/tools.md +70 -0
- package/docs/usage-examples.md +106 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PaPut MCP Server
|
|
2
2
|
|
|
3
|
-
PaPut MCP Server connects [PaPut](https://paput.io) to AI assistants through the Model Context Protocol (MCP).
|
|
3
|
+
PaPut MCP Server connects [PaPut](https://paput.io) to AI assistants through the Model Context Protocol (MCP). Remote HTTP mode lets Claude, ChatGPT, Codex, Claude Code, and other MCP clients create, search, and organize PaPut memos, notes, and skill sheets through OAuth. Local CLI mode is convenient for Claude Code and Codex workflows that need local session scanning, pending knowledge candidates, and the local PaPut cache.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -38,23 +38,53 @@ npm install -g paput-mcp
|
|
|
38
38
|
|
|
39
39
|
## MCP Configuration
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
### Remote HTTP Mode
|
|
42
|
+
|
|
43
|
+
Use remote HTTP mode when you want a simple OAuth-based MCP setup for memo,
|
|
44
|
+
note, and skill sheet operations.
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
"paput": {
|
|
48
|
+
"type": "http",
|
|
49
|
+
"url": "https://mcp.paput.io"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Remote HTTP mode intentionally does not expose local cache, pending candidate,
|
|
54
|
+
or session transcript tools because the hosted server cannot access files on
|
|
55
|
+
your device. Remote HTTP mode also does not apply project-specific local
|
|
56
|
+
configuration.
|
|
57
|
+
|
|
58
|
+
### Local CLI Mode
|
|
59
|
+
|
|
60
|
+
Use local CLI mode when you want Claude Code, Codex, or another local MCP client
|
|
61
|
+
to scan local Claude/Codex sessions and keep a local pending cache. Log in once
|
|
62
|
+
with OAuth before starting the local MCP server:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx -y paput-mcp login
|
|
66
|
+
```
|
|
42
67
|
|
|
43
68
|
```json
|
|
44
69
|
"paput": {
|
|
45
70
|
"command": "npx",
|
|
46
71
|
"args": ["-y", "paput-mcp"],
|
|
47
72
|
"env": {
|
|
48
|
-
"PAPUT_API_KEY": "your-api-key",
|
|
49
73
|
"PAPUT_PROJECT_MATCH": "optional project name fragment"
|
|
50
74
|
}
|
|
51
75
|
}
|
|
52
76
|
```
|
|
53
77
|
|
|
78
|
+
The login command stores OAuth tokens under `~/.paput/oauth.json` by default.
|
|
79
|
+
The `~/.paput` directory is created with `0700` permissions and the token file is
|
|
80
|
+
written with `0600` permissions. To revoke and remove the local token cache, run:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx -y paput-mcp logout
|
|
84
|
+
```
|
|
85
|
+
|
|
54
86
|
### Environment Variables
|
|
55
87
|
|
|
56
|
-
- `PAPUT_API_KEY` - Required PaPut API key.
|
|
57
|
-
- `PAPUT_API_URL` - Optional API URL. Defaults to `https://api.paput.io`.
|
|
58
88
|
- `PAPUT_PROJECT_MATCH` - Optional project name fragment for automatic project linking when creating or updating memos.
|
|
59
89
|
- `PAPUT_HOME` - Optional PaPut local data directory. Defaults to `~/.paput`.
|
|
60
90
|
- `PAPUT_CACHE_DIR` - Optional cache directory for knowledge capture data.
|
|
@@ -129,6 +159,8 @@ Claude can call skills such as `/paput-save`. Codex can call `$paput-save` or us
|
|
|
129
159
|
|
|
130
160
|
## Available Tools
|
|
131
161
|
|
|
162
|
+
Detailed public tool documentation is available in [docs/tools.md](docs/tools.md).
|
|
163
|
+
|
|
132
164
|
### Memo Management
|
|
133
165
|
|
|
134
166
|
- `paput_create_memo` - Create a PaPut memo directly.
|
|
@@ -176,6 +208,8 @@ Write and destructive tools should be used only when the user intent is clear. I
|
|
|
176
208
|
|
|
177
209
|
## Usage Examples
|
|
178
210
|
|
|
211
|
+
Additional public examples are available in [docs/usage-examples.md](docs/usage-examples.md).
|
|
212
|
+
|
|
179
213
|
### 1. Avoid duplicate knowledge before saving
|
|
180
214
|
|
|
181
215
|
```text
|
|
@@ -221,3 +255,10 @@ PaPut MCP stores local data under `~/.paput` by default.
|
|
|
221
255
|
skills/ # Canonical skills linked into Claude/Codex
|
|
222
256
|
cache/ # Synced memos, pending candidates, and processed sessions
|
|
223
257
|
```
|
|
258
|
+
|
|
259
|
+
## Public Documents
|
|
260
|
+
|
|
261
|
+
- [Privacy Policy](docs/privacy-policy.md)
|
|
262
|
+
- [Usage Examples](docs/usage-examples.md)
|
|
263
|
+
- [Tools And Use Cases](docs/tools.md)
|
|
264
|
+
- [MCP Directory Submission Notes](docs/directory-submission.md)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
|
+
const endpoint = process.env.MCP_HTTP_URL ?? process.argv[2];
|
|
5
|
+
if (!endpoint) {
|
|
6
|
+
console.error('Usage: MCP_HTTP_URL=https://example.onrender.com npm run check:http');
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
const client = new Client({
|
|
10
|
+
name: 'paput-mcp-http-check',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
}, {
|
|
13
|
+
capabilities: {},
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const transport = new StreamableHTTPClientTransport(new URL(endpoint));
|
|
17
|
+
await client.connect(transport);
|
|
18
|
+
const result = await client.listTools();
|
|
19
|
+
const toolNames = result.tools.map((tool) => tool.name);
|
|
20
|
+
console.log(`Connected to ${endpoint}`);
|
|
21
|
+
console.log(`Tools: ${toolNames.length}`);
|
|
22
|
+
console.log(toolNames.join('\n'));
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await client.close();
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=check-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-http.js","sourceRoot":"","sources":["../src/check-http.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAEnG,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE7D,IAAI,CAAC,QAAQ,EAAE,CAAC;IACd,OAAO,CAAC,KAAK,CACX,qEAAqE,CACtE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,sBAAsB;IAC5B,OAAO,EAAE,OAAO;CACjB,EACD;IACE,YAAY,EAAE,EAAE;CACjB,CACF,CAAC;AAEF,IAAI,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvE,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IACxC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAExD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,UAAU,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpC,CAAC;QAAS,CAAC;IACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
|
+
import { login } from './login.js';
|
|
2
|
+
import { logout } from './logout.js';
|
|
1
3
|
import { setupAi } from './setup-ai.js';
|
|
2
|
-
export function runCli(args) {
|
|
4
|
+
export async function runCli(args) {
|
|
3
5
|
const command = args[0];
|
|
4
6
|
if (!command)
|
|
5
7
|
return false;
|
|
8
|
+
if (command === 'login') {
|
|
9
|
+
try {
|
|
10
|
+
await login(args.slice(1));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.error(error instanceof Error ? error.message : error);
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (command === 'logout') {
|
|
19
|
+
try {
|
|
20
|
+
await logout(args.slice(1));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error(error instanceof Error ? error.message : error);
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
6
28
|
if (command === 'setup-ai') {
|
|
7
29
|
setupAi(args.slice(1));
|
|
8
30
|
return true;
|
|
@@ -19,9 +41,15 @@ export function runCli(args) {
|
|
|
19
41
|
function printHelp() {
|
|
20
42
|
console.log(`Usage:
|
|
21
43
|
paput-mcp Start the MCP server
|
|
44
|
+
paput-mcp login Log in to PaPut with OAuth for local CLI mode
|
|
45
|
+
paput-mcp logout Revoke and remove the local OAuth token cache
|
|
22
46
|
paput-mcp setup-ai Set up PaPut integration for Claude/Codex
|
|
23
47
|
|
|
24
48
|
Options:
|
|
49
|
+
--api-url <URL> PaPut API URL for login. Defaults to PAPUT_API_URL or https://api.paput.io
|
|
50
|
+
--scopes <SCOPES> Comma-separated OAuth scopes for login
|
|
51
|
+
--no-open Print the login URL without opening a browser
|
|
52
|
+
--local-only Remove local token cache without remote revoke during logout
|
|
25
53
|
--force Refresh existing PaPut-managed links and rules
|
|
26
54
|
--no-rules Do not update global rules
|
|
27
55
|
--claude-only Configure Claude only
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,UAAU,MAAM,CAAC,IAAc;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAE3B,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC9D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACnE,SAAS,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;CAeb,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
import { buildStoredOAuthSession, fetchAuthorizationServerMetadata, getOAuthSessionPath, writeStoredOAuthSession, } from '../services/oauth/local-auth.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const DEFAULT_SCOPES = 'paput.read paput.write';
|
|
8
|
+
export async function login(args) {
|
|
9
|
+
const options = parseLoginOptions(args);
|
|
10
|
+
const metadata = await fetchAuthorizationServerMetadata(options.apiUrl);
|
|
11
|
+
const callback = await startCallbackServer();
|
|
12
|
+
const callbackPromise = callback.waitForCallback();
|
|
13
|
+
try {
|
|
14
|
+
const client = await registerClient({
|
|
15
|
+
endpoint: metadata.registration_endpoint,
|
|
16
|
+
redirectUri: callback.redirectUri,
|
|
17
|
+
scopes: options.scopes,
|
|
18
|
+
});
|
|
19
|
+
const codeVerifier = randomToken();
|
|
20
|
+
const state = randomToken();
|
|
21
|
+
const authorizationUrl = new URL(metadata.authorization_endpoint);
|
|
22
|
+
authorizationUrl.searchParams.set('response_type', 'code');
|
|
23
|
+
authorizationUrl.searchParams.set('client_id', client.client_id);
|
|
24
|
+
authorizationUrl.searchParams.set('redirect_uri', callback.redirectUri);
|
|
25
|
+
authorizationUrl.searchParams.set('scope', options.scopes);
|
|
26
|
+
authorizationUrl.searchParams.set('state', state);
|
|
27
|
+
authorizationUrl.searchParams.set('code_challenge', pkceChallenge(codeVerifier));
|
|
28
|
+
authorizationUrl.searchParams.set('code_challenge_method', 'S256');
|
|
29
|
+
console.log('Opening PaPut OAuth login in your browser.');
|
|
30
|
+
console.log(`If it does not open, visit:\n${authorizationUrl.toString()}`);
|
|
31
|
+
if (!options.noOpen) {
|
|
32
|
+
await openBrowser(authorizationUrl.toString());
|
|
33
|
+
}
|
|
34
|
+
const callbackResult = await callbackPromise;
|
|
35
|
+
if (callbackResult.state !== state) {
|
|
36
|
+
throw new Error('OAuth state mismatch.');
|
|
37
|
+
}
|
|
38
|
+
const token = await exchangeCode({
|
|
39
|
+
clientId: client.client_id,
|
|
40
|
+
code: callbackResult.code,
|
|
41
|
+
codeVerifier,
|
|
42
|
+
redirectUri: callback.redirectUri,
|
|
43
|
+
tokenEndpoint: metadata.token_endpoint,
|
|
44
|
+
});
|
|
45
|
+
writeStoredOAuthSession(buildStoredOAuthSession({
|
|
46
|
+
apiUrl: options.apiUrl,
|
|
47
|
+
clientId: client.client_id,
|
|
48
|
+
issuer: metadata.issuer,
|
|
49
|
+
redirectUri: callback.redirectUri,
|
|
50
|
+
token,
|
|
51
|
+
}));
|
|
52
|
+
console.log(`PaPut OAuth login completed.`);
|
|
53
|
+
console.log(`Token cache: ${getOAuthSessionPath()}`);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await callback.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function parseLoginOptions(args) {
|
|
60
|
+
const options = {
|
|
61
|
+
apiUrl: process.env.PAPUT_API_URL ?? 'https://api.paput.io',
|
|
62
|
+
noOpen: false,
|
|
63
|
+
scopes: DEFAULT_SCOPES,
|
|
64
|
+
};
|
|
65
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
66
|
+
const arg = args[index];
|
|
67
|
+
if (arg === '--help' || arg === '-h') {
|
|
68
|
+
printLoginHelp();
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
else if (arg === '--api-url') {
|
|
72
|
+
options.apiUrl = requireValue(args, (index += 1), '--api-url');
|
|
73
|
+
}
|
|
74
|
+
else if (arg === '--scopes') {
|
|
75
|
+
options.scopes = requireValue(args, (index += 1), '--scopes')
|
|
76
|
+
.split(',')
|
|
77
|
+
.map((scope) => scope.trim())
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.join(' ');
|
|
80
|
+
}
|
|
81
|
+
else if (arg === '--no-open') {
|
|
82
|
+
options.noOpen = true;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new Error(`Unknown login option: ${arg}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return options;
|
|
89
|
+
}
|
|
90
|
+
function printLoginHelp() {
|
|
91
|
+
console.log(`Usage:
|
|
92
|
+
paput-mcp login [options]
|
|
93
|
+
|
|
94
|
+
Options:
|
|
95
|
+
--api-url <URL> PaPut API URL. Defaults to PAPUT_API_URL or https://api.paput.io
|
|
96
|
+
--scopes <SCOPES> Comma-separated OAuth scopes. Defaults to paput.read,paput.write
|
|
97
|
+
--no-open Print the login URL without opening a browser
|
|
98
|
+
`);
|
|
99
|
+
}
|
|
100
|
+
function requireValue(args, index, option) {
|
|
101
|
+
const value = args[index];
|
|
102
|
+
if (!value)
|
|
103
|
+
throw new Error(`${option} requires a value.`);
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
async function registerClient(params) {
|
|
107
|
+
const response = await fetch(params.endpoint, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
110
|
+
body: JSON.stringify({
|
|
111
|
+
redirect_uris: [params.redirectUri],
|
|
112
|
+
token_endpoint_auth_method: 'none',
|
|
113
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
114
|
+
response_types: ['code'],
|
|
115
|
+
client_name: 'PaPut MCP Local CLI',
|
|
116
|
+
client_uri: 'https://github.com/mizulba-dev/paput-mcp',
|
|
117
|
+
software_id: 'paput-mcp',
|
|
118
|
+
software_version: 'local',
|
|
119
|
+
scope: params.scopes,
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
if (!response.ok) {
|
|
123
|
+
throw new Error(`OAuth client registration failed: HTTP ${response.status}`);
|
|
124
|
+
}
|
|
125
|
+
const client = (await response.json());
|
|
126
|
+
if (!client.client_id) {
|
|
127
|
+
throw new Error('OAuth client registration response is missing client_id.');
|
|
128
|
+
}
|
|
129
|
+
return client;
|
|
130
|
+
}
|
|
131
|
+
async function exchangeCode(params) {
|
|
132
|
+
const response = await fetch(params.tokenEndpoint, {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
135
|
+
body: new URLSearchParams({
|
|
136
|
+
grant_type: 'authorization_code',
|
|
137
|
+
client_id: params.clientId,
|
|
138
|
+
code: params.code,
|
|
139
|
+
redirect_uri: params.redirectUri,
|
|
140
|
+
code_verifier: params.codeVerifier,
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new Error(`OAuth token exchange failed: HTTP ${response.status}`);
|
|
145
|
+
}
|
|
146
|
+
return (await response.json());
|
|
147
|
+
}
|
|
148
|
+
async function startCallbackServer() {
|
|
149
|
+
let resolveCallback;
|
|
150
|
+
let rejectCallback;
|
|
151
|
+
const callbackPromise = new Promise((resolve, reject) => {
|
|
152
|
+
resolveCallback = resolve;
|
|
153
|
+
rejectCallback = reject;
|
|
154
|
+
});
|
|
155
|
+
const server = createServer((req, res) => {
|
|
156
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
157
|
+
if (url.pathname !== '/oauth/callback') {
|
|
158
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
159
|
+
res.end('Not found');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const error = url.searchParams.get('error');
|
|
163
|
+
if (error) {
|
|
164
|
+
rejectCallback?.(new Error(`OAuth authorization failed: ${error}`));
|
|
165
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
166
|
+
res.end('Authorization failed. You may close this window.');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const code = url.searchParams.get('code');
|
|
170
|
+
const state = url.searchParams.get('state');
|
|
171
|
+
if (!code || !state) {
|
|
172
|
+
rejectCallback?.(new Error('OAuth callback is missing code or state.'));
|
|
173
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
174
|
+
res.end('Invalid callback. You may close this window.');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
resolveCallback?.({ code, state });
|
|
178
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
179
|
+
res.end('Authorization successful. You may close this window.');
|
|
180
|
+
});
|
|
181
|
+
await listen(server);
|
|
182
|
+
const address = server.address();
|
|
183
|
+
return {
|
|
184
|
+
close: () => close(server),
|
|
185
|
+
redirectUri: `http://127.0.0.1:${address.port}/oauth/callback`,
|
|
186
|
+
waitForCallback: () => callbackPromise,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async function listen(server) {
|
|
190
|
+
await new Promise((resolve, reject) => {
|
|
191
|
+
server.once('error', reject);
|
|
192
|
+
server.listen(0, '127.0.0.1', () => {
|
|
193
|
+
server.off('error', reject);
|
|
194
|
+
resolve();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async function close(server) {
|
|
199
|
+
await new Promise((resolve, reject) => {
|
|
200
|
+
server.close((error) => {
|
|
201
|
+
if (error)
|
|
202
|
+
reject(error);
|
|
203
|
+
else
|
|
204
|
+
resolve();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function openBrowser(url) {
|
|
209
|
+
const command = process.platform === 'darwin'
|
|
210
|
+
? 'open'
|
|
211
|
+
: process.platform === 'win32'
|
|
212
|
+
? 'cmd'
|
|
213
|
+
: 'xdg-open';
|
|
214
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
215
|
+
try {
|
|
216
|
+
await execFileAsync(command, args);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
console.warn('Could not open the browser automatically.');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function randomToken() {
|
|
223
|
+
return base64Url(randomBytes(32));
|
|
224
|
+
}
|
|
225
|
+
function pkceChallenge(verifier) {
|
|
226
|
+
return base64Url(createHash('sha256').update(verifier).digest());
|
|
227
|
+
}
|
|
228
|
+
function base64Url(buffer) {
|
|
229
|
+
return buffer
|
|
230
|
+
.toString('base64')
|
|
231
|
+
.replace(/\+/g, '-')
|
|
232
|
+
.replace(/\//g, '_')
|
|
233
|
+
.replace(/=+$/g, '');
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/cli/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { deleteStoredOAuthSession, fetchAuthorizationServerMetadata, readStoredOAuthSession, } from '../services/oauth/local-auth.js';
|
|
2
|
+
export async function logout(args) {
|
|
3
|
+
const options = parseLogoutOptions(args);
|
|
4
|
+
const session = readStoredOAuthSession();
|
|
5
|
+
if (!session) {
|
|
6
|
+
deleteStoredOAuthSession();
|
|
7
|
+
console.log('No PaPut OAuth session was found.');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!options.localOnly) {
|
|
11
|
+
try {
|
|
12
|
+
await revokeRefreshToken(session);
|
|
13
|
+
console.log('PaPut OAuth refresh token was revoked.');
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.warn(`Could not revoke the remote token: ${error instanceof Error ? error.message : String(error)}`);
|
|
17
|
+
console.warn('Removing the local token cache anyway.');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
deleteStoredOAuthSession();
|
|
21
|
+
console.log('Local PaPut OAuth token cache was removed.');
|
|
22
|
+
}
|
|
23
|
+
function parseLogoutOptions(args) {
|
|
24
|
+
const options = { localOnly: false };
|
|
25
|
+
for (const arg of args) {
|
|
26
|
+
if (arg === '--help' || arg === '-h') {
|
|
27
|
+
printLogoutHelp();
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
else if (arg === '--local-only') {
|
|
31
|
+
options.localOnly = true;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw new Error(`Unknown logout option: ${arg}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return options;
|
|
38
|
+
}
|
|
39
|
+
async function revokeRefreshToken(session) {
|
|
40
|
+
const metadata = await fetchAuthorizationServerMetadata(session.api_url);
|
|
41
|
+
if (!metadata.revocation_endpoint) {
|
|
42
|
+
throw new Error('OAuth metadata does not provide a revocation endpoint.');
|
|
43
|
+
}
|
|
44
|
+
const response = await fetch(metadata.revocation_endpoint, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
47
|
+
body: new URLSearchParams({
|
|
48
|
+
client_id: session.client_id,
|
|
49
|
+
token: session.refresh_token,
|
|
50
|
+
token_type_hint: 'refresh_token',
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
throw new Error(`HTTP ${response.status}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function printLogoutHelp() {
|
|
58
|
+
console.log(`Usage:
|
|
59
|
+
paput-mcp logout [options]
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
--local-only Remove the local token cache without calling the revoke endpoint
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/cli/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,gCAAgC,EAChC,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAMzC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IACzC,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAC;IAEzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,wBAAwB,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,sCACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CACH,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,wBAAwB,EAAE,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAc;IACxC,MAAM,OAAO,GAAkB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAEpD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,eAAe,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,GAAG,KAAK,cAAc,EAAE,CAAC;YAClC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,OAIjC;IACC,MAAM,QAAQ,GAAG,MAAM,gCAAgC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,mBAAmB,EAAE;QACzD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,OAAO,CAAC,aAAa;YAC5B,eAAe,EAAE,eAAe;SACjC,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,CAAC,GAAG,CAAC;;;;;CAKb,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createMemo } from '../../services/api/memo.js';
|
|
2
|
-
import {
|
|
3
|
-
export async function handleCreateMemo(args, apiClient) {
|
|
2
|
+
import { resolveMemoProjects } from '../memo-projects.js';
|
|
3
|
+
export async function handleCreateMemo(args, apiClient, context) {
|
|
4
4
|
if (!args) {
|
|
5
5
|
return {
|
|
6
6
|
content: [
|
|
@@ -39,27 +39,7 @@ export async function handleCreateMemo(args, apiClient) {
|
|
|
39
39
|
.filter((item) => typeof item === 'string')
|
|
40
40
|
.map((name) => ({ name }));
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
if (Array.isArray(args.projects)) {
|
|
44
|
-
params.projects = args.projects.filter((item) => typeof item === 'object' &&
|
|
45
|
-
item !== null &&
|
|
46
|
-
'id' in item &&
|
|
47
|
-
typeof item.id === 'number');
|
|
48
|
-
}
|
|
49
|
-
else if (!args.projects && process.env.PAPUT_PROJECT_MATCH) {
|
|
50
|
-
// When configured, search for a project and link it automatically
|
|
51
|
-
try {
|
|
52
|
-
const projects = await searchSkillSheetProjects(apiClient, process.env.PAPUT_PROJECT_MATCH);
|
|
53
|
-
if (projects.length > 0) {
|
|
54
|
-
// Use the first matched project
|
|
55
|
-
params.projects = [projects[0]];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
// Continue creating the memo even if project search fails
|
|
60
|
-
console.error('Failed to search projects:', error);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
42
|
+
params.projects = await resolveMemoProjects(args, apiClient, context);
|
|
63
43
|
try {
|
|
64
44
|
const result = await createMemo(apiClient, params);
|
|
65
45
|
if (!result.success) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/handlers/create-memo/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/handlers/create-memo/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { searchSkillSheetProjects } from '../services/api/skill-sheet.js';
|
|
2
|
+
export async function resolveMemoProjects(args, apiClient, context) {
|
|
3
|
+
if (Array.isArray(args.projects)) {
|
|
4
|
+
return args.projects.filter((item) => typeof item === 'object' &&
|
|
5
|
+
item !== null &&
|
|
6
|
+
'id' in item &&
|
|
7
|
+
typeof item.id === 'number');
|
|
8
|
+
}
|
|
9
|
+
const projectMatch = getProjectMatch(args, context);
|
|
10
|
+
if (!projectMatch)
|
|
11
|
+
return undefined;
|
|
12
|
+
try {
|
|
13
|
+
const projects = await searchSkillSheetProjects(apiClient, projectMatch);
|
|
14
|
+
return projects.length > 0 ? [projects[0]] : undefined;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error('Failed to search projects:', error);
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function getProjectMatch(args, context) {
|
|
22
|
+
const explicit = typeof args.project_match === 'string' ? args.project_match.trim() : '';
|
|
23
|
+
if (explicit)
|
|
24
|
+
return explicit;
|
|
25
|
+
if (context?.projectMatch)
|
|
26
|
+
return context.projectMatch;
|
|
27
|
+
return process.env.PAPUT_PROJECT_MATCH;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=memo-projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo-projects.js","sourceRoot":"","sources":["../../src/handlers/memo-projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAK1E,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAA6B,EAC7B,SAAoB,EACpB,OAAqB;IAErB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CACzB,CAAC,IAAI,EAA4B,EAAE,CACjC,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,IAAI,IAAI,IAAI;YACZ,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,CAC9B,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACzE,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,IAA6B,EAC7B,OAAqB;IAErB,MAAM,QAAQ,GACZ,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,OAAO,EAAE,YAAY;QAAE,OAAO,OAAO,CAAC,YAAY,CAAC;IACvD,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;AACzC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { searchSkillSheetProjects } from '../../services/api/skill-sheet.js';
|
|
2
1
|
import { updateMemo } from '../../services/api/memo.js';
|
|
3
|
-
|
|
2
|
+
import { resolveMemoProjects } from '../memo-projects.js';
|
|
3
|
+
export async function handleUpdateMemo(args, apiClient, context) {
|
|
4
4
|
if (!args) {
|
|
5
5
|
return {
|
|
6
6
|
content: [
|
|
@@ -47,27 +47,7 @@ export async function handleUpdateMemo(args, apiClient) {
|
|
|
47
47
|
is_public: args.is_public,
|
|
48
48
|
categories,
|
|
49
49
|
};
|
|
50
|
-
|
|
51
|
-
if (Array.isArray(args.projects)) {
|
|
52
|
-
params.projects = args.projects.filter((item) => typeof item === 'object' &&
|
|
53
|
-
item !== null &&
|
|
54
|
-
'id' in item &&
|
|
55
|
-
typeof item.id === 'number');
|
|
56
|
-
}
|
|
57
|
-
else if (!args.projects && process.env.PAPUT_PROJECT_MATCH) {
|
|
58
|
-
// When configured, search for a project and link it automatically
|
|
59
|
-
try {
|
|
60
|
-
const projects = await searchSkillSheetProjects(apiClient, process.env.PAPUT_PROJECT_MATCH);
|
|
61
|
-
if (projects.length > 0) {
|
|
62
|
-
// Use the first matched project
|
|
63
|
-
params.projects = [projects[0]];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
// Continue updating the memo even if project search fails
|
|
68
|
-
console.error('Failed to search projects:', error);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
50
|
+
params.projects = await resolveMemoProjects(args, apiClient, context);
|
|
71
51
|
try {
|
|
72
52
|
const result = await updateMemo(apiClient, params);
|
|
73
53
|
if (!result.success) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/handlers/update-memo/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/handlers/update-memo/handler.ts"],"names":[],"mappings":"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"}
|