freeagent-mcp-server 1.0.1 → 1.1.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 +48 -16
- package/build/auth.d.ts +17 -0
- package/build/auth.js +195 -0
- package/build/auth.js.map +1 -0
- package/build/client.d.ts +2 -2
- package/build/client.js +8 -4
- package/build/client.js.map +1 -1
- package/build/index.js +78 -30
- package/build/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ MCP server for the [FreeAgent](https://www.freeagent.com/) accounting API. Provi
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
+
- **OAuth2 Authentication** - Built-in browser-based auth flow with automatic token refresh
|
|
10
11
|
- **Company** - Company info, business categories, tax timeline
|
|
11
12
|
- **Users** - List, get, create, update, and delete users
|
|
12
13
|
- **Contacts** - Full CRUD for clients and suppliers
|
|
@@ -24,15 +25,36 @@ MCP server for the [FreeAgent](https://www.freeagent.com/) accounting API. Provi
|
|
|
24
25
|
|
|
25
26
|
## Prerequisites
|
|
26
27
|
|
|
27
|
-
You need a FreeAgent account and OAuth2 access token. To get one:
|
|
28
|
-
|
|
29
28
|
1. Sign up for a [FreeAgent Developer](https://dev.freeagent.com/) account
|
|
30
29
|
2. Create a sandbox account for testing
|
|
31
|
-
3. Register an application
|
|
32
|
-
4.
|
|
30
|
+
3. Register an application in the Developer Dashboard
|
|
31
|
+
4. Set the **OAuth redirect URI** to `http://localhost:3456/callback`
|
|
32
|
+
5. Note your **Client ID** and **Client Secret**
|
|
33
33
|
|
|
34
34
|
See the [FreeAgent API Quick Start](https://dev.freeagent.com/docs/quick_start) for detailed instructions.
|
|
35
35
|
|
|
36
|
+
## Getting Started
|
|
37
|
+
|
|
38
|
+
### 1. Set environment variables
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export FREEAGENT_CLIENT_ID="your_client_id"
|
|
42
|
+
export FREEAGENT_CLIENT_SECRET="your_client_secret"
|
|
43
|
+
# export FREEAGENT_SANDBOX=false # uncomment for production accounts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Authenticate (one-time)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx freeagent-mcp-server auth
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This opens your browser to authorize the app. After approval, tokens are saved to `~/.freeagent-mcp/tokens.json` and automatically refreshed when they expire.
|
|
53
|
+
|
|
54
|
+
### 3. Configure your MCP client
|
|
55
|
+
|
|
56
|
+
See the [Configuration](#configuration) section below.
|
|
57
|
+
|
|
36
58
|
## Installation
|
|
37
59
|
|
|
38
60
|
### Using npx (recommended)
|
|
@@ -64,13 +86,13 @@ npm start
|
|
|
64
86
|
|
|
65
87
|
| Variable | Required | Description |
|
|
66
88
|
|----------|----------|-------------|
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
89
|
+
| `FREEAGENT_CLIENT_ID` | Yes* | OAuth2 client ID from Developer Dashboard |
|
|
90
|
+
| `FREEAGENT_CLIENT_SECRET` | Yes* | OAuth2 client secret from Developer Dashboard |
|
|
91
|
+
| `FREEAGENT_SANDBOX` | No | Set to `false` for production (defaults to `true`) |
|
|
92
|
+
| `FREEAGENT_ACCESS_TOKEN` | No | Legacy: direct access token (skips stored token flow) |
|
|
93
|
+
| `FREEAGENT_BASE_URL` | No | Override API base URL |
|
|
69
94
|
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
FREEAGENT_BASE_URL=https://api.freeagent.com/v2
|
|
73
|
-
```
|
|
95
|
+
*Not required if using `FREEAGENT_ACCESS_TOKEN` directly.
|
|
74
96
|
|
|
75
97
|
### Claude Desktop
|
|
76
98
|
|
|
@@ -83,7 +105,8 @@ Add to your `claude_desktop_config.json`:
|
|
|
83
105
|
"command": "npx",
|
|
84
106
|
"args": ["-y", "freeagent-mcp-server"],
|
|
85
107
|
"env": {
|
|
86
|
-
"
|
|
108
|
+
"FREEAGENT_CLIENT_ID": "your_client_id",
|
|
109
|
+
"FREEAGENT_CLIENT_SECRET": "your_client_secret"
|
|
87
110
|
}
|
|
88
111
|
}
|
|
89
112
|
}
|
|
@@ -101,7 +124,8 @@ Add to your `.mcp.json`:
|
|
|
101
124
|
"command": "npx",
|
|
102
125
|
"args": ["-y", "freeagent-mcp-server"],
|
|
103
126
|
"env": {
|
|
104
|
-
"
|
|
127
|
+
"FREEAGENT_CLIENT_ID": "your_client_id",
|
|
128
|
+
"FREEAGENT_CLIENT_SECRET": "your_client_secret"
|
|
105
129
|
}
|
|
106
130
|
}
|
|
107
131
|
}
|
|
@@ -114,8 +138,10 @@ Add to your `.mcp.json`:
|
|
|
114
138
|
freeagent-mcp/
|
|
115
139
|
├── src/
|
|
116
140
|
│ ├── index.ts # Entry point, server setup
|
|
141
|
+
│ ├── auth.ts # OAuth2 flow, token storage & refresh
|
|
117
142
|
│ ├── client.ts # FreeAgent API HTTP client
|
|
118
143
|
│ ├── utils.ts # Shared utilities (responses, logging)
|
|
144
|
+
│ ├── auth.test.ts # Auth module tests
|
|
119
145
|
│ ├── client.test.ts # Client tests
|
|
120
146
|
│ ├── utils.test.ts # Utils tests
|
|
121
147
|
│ └── tools/
|
|
@@ -336,17 +362,23 @@ npm run format
|
|
|
336
362
|
|
|
337
363
|
## Troubleshooting
|
|
338
364
|
|
|
339
|
-
**"Missing
|
|
340
|
-
Set
|
|
365
|
+
**"Missing credentials" error on startup**
|
|
366
|
+
Set `FREEAGENT_CLIENT_ID` and `FREEAGENT_CLIENT_SECRET` environment variables, then run `npx freeagent-mcp-server auth` to authenticate.
|
|
367
|
+
|
|
368
|
+
**"No stored tokens found"**
|
|
369
|
+
You need to complete the one-time auth flow first: `npx freeagent-mcp-server auth`
|
|
370
|
+
|
|
371
|
+
**Authentication times out**
|
|
372
|
+
Ensure port 3456 is available and your browser can reach `http://localhost:3456/callback`. Check that your FreeAgent app's redirect URI is set to `http://localhost:3456/callback`.
|
|
341
373
|
|
|
342
374
|
**401 Unauthorized errors**
|
|
343
|
-
Your
|
|
375
|
+
Your tokens may have been revoked. Re-run `npx freeagent-mcp-server auth` to re-authenticate.
|
|
344
376
|
|
|
345
377
|
**"FreeAgent API error (403)"**
|
|
346
378
|
Your token may not have the required permission level. Check that your FreeAgent app has the appropriate access scopes.
|
|
347
379
|
|
|
348
380
|
**Sandbox vs Production**
|
|
349
|
-
By default the server connects to the FreeAgent sandbox. Set `
|
|
381
|
+
By default the server connects to the FreeAgent sandbox. Set `FREEAGENT_SANDBOX=false` for production.
|
|
350
382
|
|
|
351
383
|
**Tool not found**
|
|
352
384
|
Ensure you're using the correct tool name with the `freeagent_` prefix (e.g., `freeagent_list_invoices`, not `list_invoices`).
|
package/build/auth.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface OAuthConfig {
|
|
2
|
+
clientId: string;
|
|
3
|
+
clientSecret: string;
|
|
4
|
+
sandbox: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface StoredTokens {
|
|
7
|
+
access_token: string;
|
|
8
|
+
refresh_token: string;
|
|
9
|
+
expires_at: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function getApiBase(sandbox: boolean): string;
|
|
12
|
+
export declare function loadTokens(): StoredTokens | null;
|
|
13
|
+
export declare function saveTokens(tokens: StoredTokens): void;
|
|
14
|
+
export declare function isTokenExpired(tokens: StoredTokens): boolean;
|
|
15
|
+
export declare function refreshAccessToken(config: OAuthConfig, refreshToken: string): Promise<StoredTokens>;
|
|
16
|
+
export declare function getValidAccessToken(config: OAuthConfig): Promise<string>;
|
|
17
|
+
export declare function runAuthFlow(config: OAuthConfig): Promise<void>;
|
package/build/auth.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
import { randomBytes } from "node:crypto";
|
|
7
|
+
import { TOKEN_BUFFER_MS } from "./utils.js";
|
|
8
|
+
const TOKEN_DIR = join(homedir(), ".freeagent-mcp");
|
|
9
|
+
const TOKEN_FILE = join(TOKEN_DIR, "tokens.json");
|
|
10
|
+
const CALLBACK_PORT = 3456;
|
|
11
|
+
const AUTH_TIMEOUT_MS = 120_000;
|
|
12
|
+
export function getApiBase(sandbox) {
|
|
13
|
+
return sandbox
|
|
14
|
+
? "https://api.sandbox.freeagent.com/v2"
|
|
15
|
+
: "https://api.freeagent.com/v2";
|
|
16
|
+
}
|
|
17
|
+
export function loadTokens() {
|
|
18
|
+
try {
|
|
19
|
+
const data = readFileSync(TOKEN_FILE, "utf-8");
|
|
20
|
+
return JSON.parse(data);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function saveTokens(tokens) {
|
|
27
|
+
mkdirSync(TOKEN_DIR, { recursive: true });
|
|
28
|
+
writeFileSync(TOKEN_FILE, JSON.stringify(tokens, null, 2), { mode: 0o600 });
|
|
29
|
+
try {
|
|
30
|
+
chmodSync(TOKEN_FILE, 0o600);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// chmod may fail on some platforms, file was already created with mode
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function isTokenExpired(tokens) {
|
|
37
|
+
return Date.now() >= tokens.expires_at - TOKEN_BUFFER_MS;
|
|
38
|
+
}
|
|
39
|
+
export async function refreshAccessToken(config, refreshToken) {
|
|
40
|
+
const base = getApiBase(config.sandbox);
|
|
41
|
+
const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64");
|
|
42
|
+
const response = await fetch(`${base}/token_endpoint`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `Basic ${credentials}`,
|
|
46
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
47
|
+
},
|
|
48
|
+
body: new URLSearchParams({
|
|
49
|
+
grant_type: "refresh_token",
|
|
50
|
+
refresh_token: refreshToken,
|
|
51
|
+
}).toString(),
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const text = await response.text();
|
|
55
|
+
throw new Error(`Token refresh failed (${response.status}): ${text}`);
|
|
56
|
+
}
|
|
57
|
+
const data = (await response.json());
|
|
58
|
+
return {
|
|
59
|
+
access_token: data.access_token,
|
|
60
|
+
refresh_token: data.refresh_token,
|
|
61
|
+
expires_at: Date.now() + data.expires_in * 1000,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
let refreshPromise = null;
|
|
65
|
+
export async function getValidAccessToken(config) {
|
|
66
|
+
const tokens = loadTokens();
|
|
67
|
+
if (!tokens) {
|
|
68
|
+
throw new Error("No stored tokens found. Run `npx freeagent-mcp-server auth` to authenticate.");
|
|
69
|
+
}
|
|
70
|
+
if (!isTokenExpired(tokens)) {
|
|
71
|
+
return tokens.access_token;
|
|
72
|
+
}
|
|
73
|
+
// Mutex: if a refresh is already in flight, wait for it
|
|
74
|
+
if (refreshPromise) {
|
|
75
|
+
const refreshed = await refreshPromise;
|
|
76
|
+
return refreshed.access_token;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
refreshPromise = refreshAccessToken(config, tokens.refresh_token);
|
|
80
|
+
const newTokens = await refreshPromise;
|
|
81
|
+
saveTokens(newTokens);
|
|
82
|
+
return newTokens.access_token;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
refreshPromise = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function openBrowser(url) {
|
|
89
|
+
const platform = process.platform;
|
|
90
|
+
const cmd = platform === "darwin"
|
|
91
|
+
? "open"
|
|
92
|
+
: platform === "win32"
|
|
93
|
+
? "start"
|
|
94
|
+
: "xdg-open";
|
|
95
|
+
exec(`${cmd} "${url}"`);
|
|
96
|
+
}
|
|
97
|
+
async function exchangeCodeForTokens(config, code) {
|
|
98
|
+
const base = getApiBase(config.sandbox);
|
|
99
|
+
const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64");
|
|
100
|
+
const response = await fetch(`${base}/token_endpoint`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: {
|
|
103
|
+
Authorization: `Basic ${credentials}`,
|
|
104
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
105
|
+
},
|
|
106
|
+
body: new URLSearchParams({
|
|
107
|
+
grant_type: "authorization_code",
|
|
108
|
+
code,
|
|
109
|
+
redirect_uri: `http://localhost:${CALLBACK_PORT}/callback`,
|
|
110
|
+
}).toString(),
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const text = await response.text();
|
|
114
|
+
throw new Error(`Token exchange failed (${response.status}): ${text}`);
|
|
115
|
+
}
|
|
116
|
+
const data = (await response.json());
|
|
117
|
+
return {
|
|
118
|
+
access_token: data.access_token,
|
|
119
|
+
refresh_token: data.refresh_token,
|
|
120
|
+
expires_at: Date.now() + data.expires_in * 1000,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export async function runAuthFlow(config) {
|
|
124
|
+
const state = randomBytes(16).toString("hex");
|
|
125
|
+
const base = getApiBase(config.sandbox);
|
|
126
|
+
const authUrl = `${base}/approve_app?response_type=code` +
|
|
127
|
+
`&client_id=${encodeURIComponent(config.clientId)}` +
|
|
128
|
+
`&redirect_uri=${encodeURIComponent(`http://localhost:${CALLBACK_PORT}/callback`)}` +
|
|
129
|
+
`&state=${encodeURIComponent(state)}`;
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
const timeout = setTimeout(() => {
|
|
132
|
+
server.close();
|
|
133
|
+
reject(new Error("Authentication timed out after 120 seconds"));
|
|
134
|
+
}, AUTH_TIMEOUT_MS);
|
|
135
|
+
const server = createServer(async (req, res) => {
|
|
136
|
+
const url = new URL(req.url || "/", `http://localhost:${CALLBACK_PORT}`);
|
|
137
|
+
if (url.pathname !== "/callback") {
|
|
138
|
+
res.writeHead(404);
|
|
139
|
+
res.end("Not found");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const returnedState = url.searchParams.get("state");
|
|
143
|
+
const code = url.searchParams.get("code");
|
|
144
|
+
const error = url.searchParams.get("error");
|
|
145
|
+
if (error) {
|
|
146
|
+
res.writeHead(400);
|
|
147
|
+
res.end(`Authentication failed: ${error}`);
|
|
148
|
+
clearTimeout(timeout);
|
|
149
|
+
server.close();
|
|
150
|
+
reject(new Error(`OAuth error: ${error}`));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (returnedState !== state) {
|
|
154
|
+
res.writeHead(400);
|
|
155
|
+
res.end("State mismatch - possible CSRF attack");
|
|
156
|
+
clearTimeout(timeout);
|
|
157
|
+
server.close();
|
|
158
|
+
reject(new Error("OAuth state mismatch"));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (!code) {
|
|
162
|
+
res.writeHead(400);
|
|
163
|
+
res.end("No authorization code received");
|
|
164
|
+
clearTimeout(timeout);
|
|
165
|
+
server.close();
|
|
166
|
+
reject(new Error("No authorization code in callback"));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const tokens = await exchangeCodeForTokens(config, code);
|
|
171
|
+
saveTokens(tokens);
|
|
172
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
173
|
+
res.end("<html><body><h1>Authentication successful!</h1>" +
|
|
174
|
+
"<p>You can close this window and return to your terminal.</p>" +
|
|
175
|
+
"</body></html>");
|
|
176
|
+
clearTimeout(timeout);
|
|
177
|
+
server.close();
|
|
178
|
+
resolve();
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
res.writeHead(500);
|
|
182
|
+
res.end("Token exchange failed");
|
|
183
|
+
clearTimeout(timeout);
|
|
184
|
+
server.close();
|
|
185
|
+
reject(err);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
server.listen(CALLBACK_PORT, () => {
|
|
189
|
+
console.log(`\nOpening browser for FreeAgent authorization...`);
|
|
190
|
+
console.log(`If the browser doesn't open, visit:\n${authUrl}\n`);
|
|
191
|
+
openBrowser(authUrl);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/build/client.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export declare class FreeAgentApiError extends Error {
|
|
|
4
4
|
constructor(status: number, errorCode: string, message: string);
|
|
5
5
|
}
|
|
6
6
|
export declare class FreeAgentClient {
|
|
7
|
-
private
|
|
7
|
+
private getAccessToken;
|
|
8
8
|
private baseUrl;
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(tokenOrProvider: string | (() => Promise<string>), baseUrl?: string);
|
|
10
10
|
get<T = unknown>(path: string, params?: Record<string, string>): Promise<T>;
|
|
11
11
|
postForm<T = unknown>(path: string, body?: Record<string, string>): Promise<T>;
|
|
12
12
|
postJson<T = unknown>(path: string, body: unknown): Promise<T>;
|
package/build/client.js
CHANGED
|
@@ -27,10 +27,13 @@ function encodeFormBody(data) {
|
|
|
27
27
|
return new URLSearchParams(data).toString();
|
|
28
28
|
}
|
|
29
29
|
export class FreeAgentClient {
|
|
30
|
-
|
|
30
|
+
getAccessToken;
|
|
31
31
|
baseUrl;
|
|
32
|
-
constructor(
|
|
33
|
-
this.
|
|
32
|
+
constructor(tokenOrProvider, baseUrl) {
|
|
33
|
+
this.getAccessToken =
|
|
34
|
+
typeof tokenOrProvider === "function"
|
|
35
|
+
? tokenOrProvider
|
|
36
|
+
: async () => tokenOrProvider;
|
|
34
37
|
this.baseUrl = baseUrl || DEFAULT_BASE_URL;
|
|
35
38
|
}
|
|
36
39
|
async get(path, params) {
|
|
@@ -63,8 +66,9 @@ export class FreeAgentClient {
|
|
|
63
66
|
url.searchParams.set(k, v);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
69
|
+
const accessToken = await this.getAccessToken();
|
|
66
70
|
const headers = {
|
|
67
|
-
Authorization: `Bearer ${
|
|
71
|
+
Authorization: `Bearer ${accessToken}`,
|
|
68
72
|
Accept: "application/json",
|
|
69
73
|
"User-Agent": "freeagent-mcp/1.0.0",
|
|
70
74
|
};
|
package/build/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,sCAAsC,CAAC;AAEhE,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1B,MAAM,CAAS;IACf,SAAS,CAAS;IAElC,YAAY,MAAc,EAAE,SAAiB,EAAE,OAAe;QAC5D,KAAK,CAAC,wBAAwB,MAAM,MAAM,SAAS,MAAM,OAAO,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,SAAS,aAAa,CAAC,MAAc,EAAE,IAAY;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,EAAE,KAAK,IAAI,MAAM,EAAE,IAAI,IAAI,SAAS,CAAC;QACxD,MAAM,OAAO,GACX,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,iBAAiB;YACzB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;YAC9B,QAAQ,MAAM,EAAE,CAAC;QACnB,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,IAA4B;IAClD,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,OAAO,eAAe;IAClB,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,sCAAsC,CAAC;AAEhE,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1B,MAAM,CAAS;IACf,SAAS,CAAS;IAElC,YAAY,MAAc,EAAE,SAAiB,EAAE,OAAe;QAC5D,KAAK,CAAC,wBAAwB,MAAM,MAAM,SAAS,MAAM,OAAO,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,SAAS,aAAa,CAAC,MAAc,EAAE,IAAY;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,EAAE,KAAK,IAAI,MAAM,EAAE,IAAI,IAAI,SAAS,CAAC;QACxD,MAAM,OAAO,GACX,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,iBAAiB;YACzB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;YAC9B,QAAQ,MAAM,EAAE,CAAC;QACnB,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,IAA4B;IAClD,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,OAAO,eAAe;IAClB,cAAc,CAAwB;IACtC,OAAO,CAAS;IAExB,YACE,eAAiD,EACjD,OAAgB;QAEhB,IAAI,CAAC,cAAc;YACjB,OAAO,eAAe,KAAK,UAAU;gBACnC,CAAC,CAAC,eAAe;gBACjB,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,eAAe,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CACP,IAAY,EACZ,MAA+B;QAE/B,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,IAAY,EACZ,IAA6B;QAE7B,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAc,IAAY,EAAE,IAAa;QACrD,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,OAAO,CACX,IAAY,EACZ,IAA6B;QAE7B,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,IAAY,EAAE,IAAa;QACpD,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,SAAS,CAAc,IAAY,EAAE,IAAa;QACtD,OAAO,IAAI,CAAC,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,MAA+B;QAE/B,OAAO,IAAI,CAAC,OAAO,CAAI,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc,EACd,QAA0B,EAC1B,MAA+B;QAE/B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEpC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAChD,MAAM,OAAO,GAA2B;YACtC,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,MAAM,EAAE,kBAAkB;YAC1B,YAAY,EAAE,qBAAqB;SACpC,CAAC;QAEF,IAAI,WAA+B,CAAC;QAEpC,IAAI,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YAChC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACvC,OAAO,CAAC,cAAc,CAAC,GAAG,mCAAmC,CAAC;YAC9D,WAAW,GAAG,cAAc,CAAC,IAA8B,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC3C,MAAM;YACN,OAAO;YACP,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAO,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;CACF"}
|
package/build/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { FreeAgentClient } from "./client.js";
|
|
5
|
+
import { runAuthFlow, getValidAccessToken, getApiBase } from "./auth.js";
|
|
5
6
|
import { registerCompanyTools } from "./tools/company.js";
|
|
6
7
|
import { registerUserTools } from "./tools/users.js";
|
|
7
8
|
import { registerContactTools } from "./tools/contacts.js";
|
|
@@ -17,37 +18,84 @@ import { registerBankingTools } from "./tools/banking.js";
|
|
|
17
18
|
import { registerCategoryTools } from "./tools/categories.js";
|
|
18
19
|
import { registerAccountingTools } from "./tools/accounting.js";
|
|
19
20
|
const FREEAGENT_ACCESS_TOKEN = process.env.FREEAGENT_ACCESS_TOKEN;
|
|
21
|
+
const FREEAGENT_CLIENT_ID = process.env.FREEAGENT_CLIENT_ID;
|
|
22
|
+
const FREEAGENT_CLIENT_SECRET = process.env.FREEAGENT_CLIENT_SECRET;
|
|
23
|
+
const FREEAGENT_SANDBOX = process.env.FREEAGENT_SANDBOX !== "false";
|
|
20
24
|
const FREEAGENT_BASE_URL = process.env.FREEAGENT_BASE_URL;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
function buildOAuthConfig() {
|
|
26
|
+
if (FREEAGENT_CLIENT_ID && FREEAGENT_CLIENT_SECRET) {
|
|
27
|
+
return {
|
|
28
|
+
clientId: FREEAGENT_CLIENT_ID,
|
|
29
|
+
clientSecret: FREEAGENT_CLIENT_SECRET,
|
|
30
|
+
sandbox: FREEAGENT_SANDBOX,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
24
34
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
// Handle `npx freeagent-mcp-server auth` subcommand
|
|
36
|
+
if (process.argv[2] === "auth") {
|
|
37
|
+
const config = buildOAuthConfig();
|
|
38
|
+
if (!config) {
|
|
39
|
+
console.error("Missing FREEAGENT_CLIENT_ID and FREEAGENT_CLIENT_SECRET environment variables.\n" +
|
|
40
|
+
"Set these from your FreeAgent Developer Dashboard app credentials.");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
runAuthFlow(config)
|
|
44
|
+
.then(() => {
|
|
45
|
+
console.log("Authentication complete! Tokens saved.");
|
|
46
|
+
console.log("You can now start the MCP server.");
|
|
47
|
+
process.exit(0);
|
|
48
|
+
})
|
|
49
|
+
.catch((err) => {
|
|
50
|
+
console.error("Authentication failed:", err.message);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Normal server mode
|
|
56
|
+
let client;
|
|
57
|
+
if (FREEAGENT_ACCESS_TOKEN) {
|
|
58
|
+
// Legacy: direct access token
|
|
59
|
+
client = new FreeAgentClient(FREEAGENT_ACCESS_TOKEN, FREEAGENT_BASE_URL);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const config = buildOAuthConfig();
|
|
63
|
+
if (!config) {
|
|
64
|
+
console.error("Missing credentials. Provide one of:\n" +
|
|
65
|
+
" 1. FREEAGENT_CLIENT_ID + FREEAGENT_CLIENT_SECRET (recommended)\n" +
|
|
66
|
+
" 2. FREEAGENT_ACCESS_TOKEN (legacy)\n\n" +
|
|
67
|
+
"For option 1, run `npx freeagent-mcp-server auth` first to authenticate.");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const baseUrl = FREEAGENT_BASE_URL || getApiBase(config.sandbox);
|
|
71
|
+
client = new FreeAgentClient(() => getValidAccessToken(config), baseUrl);
|
|
72
|
+
}
|
|
73
|
+
const server = new McpServer({
|
|
74
|
+
name: "freeagent-mcp",
|
|
75
|
+
version: "1.0.0",
|
|
76
|
+
});
|
|
77
|
+
registerCompanyTools(server, client);
|
|
78
|
+
registerUserTools(server, client);
|
|
79
|
+
registerContactTools(server, client);
|
|
80
|
+
registerProjectTools(server, client);
|
|
81
|
+
registerTaskTools(server, client);
|
|
82
|
+
registerTimeslipTools(server, client);
|
|
83
|
+
registerInvoiceTools(server, client);
|
|
84
|
+
registerEstimateTools(server, client);
|
|
85
|
+
registerBillTools(server, client);
|
|
86
|
+
registerCreditNoteTools(server, client);
|
|
87
|
+
registerExpenseTools(server, client);
|
|
88
|
+
registerBankingTools(server, client);
|
|
89
|
+
registerCategoryTools(server, client);
|
|
90
|
+
registerAccountingTools(server, client);
|
|
91
|
+
async function main() {
|
|
92
|
+
const transport = new StdioServerTransport();
|
|
93
|
+
await server.connect(transport);
|
|
94
|
+
console.error("FreeAgent MCP Server running on stdio");
|
|
95
|
+
}
|
|
96
|
+
main().catch((error) => {
|
|
97
|
+
console.error("Fatal error:", error);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
48
100
|
}
|
|
49
|
-
main().catch((error) => {
|
|
50
|
-
console.error("Fatal error:", error);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
});
|
|
53
101
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,sBAAsB,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;AAClE,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAE1D,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|