mcp-sunsama 0.13.0 → 0.14.1
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/CHANGELOG.md +19 -0
- package/CONTRIBUTING.md +229 -0
- package/README.md +13 -3
- package/bun.lock +18 -24
- package/dist/auth/stdio.d.ts +4 -4
- package/dist/auth/stdio.d.ts.map +1 -1
- package/dist/auth/stdio.js +11 -10
- package/dist/main.js +10 -3
- package/dist/tools/shared.d.ts +0 -4
- package/dist/tools/shared.d.ts.map +1 -1
- package/dist/tools/shared.js +0 -7
- package/dist/tools/stream-tools.d.ts.map +1 -1
- package/dist/tools/stream-tools.js +3 -2
- package/dist/tools/task-tools.d.ts.map +1 -1
- package/dist/tools/task-tools.js +16 -15
- package/dist/tools/user-tools.d.ts.map +1 -1
- package/dist/tools/user-tools.js +3 -2
- package/dist/utils/client-resolver.d.ts +3 -3
- package/dist/utils/client-resolver.d.ts.map +1 -1
- package/dist/utils/client-resolver.js +4 -4
- package/package.json +3 -3
- package/src/auth/stdio.ts +14 -11
- package/src/main.ts +9 -3
- package/src/tools/shared.ts +0 -7
- package/src/tools/stream-tools.ts +3 -2
- package/src/tools/task-tools.ts +15 -15
- package/src/tools/user-tools.ts +3 -2
- package/src/utils/client-resolver.ts +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# mcp-sunsama
|
|
2
2
|
|
|
3
|
+
## 0.14.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix: resolve stdio authentication race condition
|
|
8
|
+
|
|
9
|
+
Fixes critical race condition in stdio authentication that caused "Global Sunsama client not initialized" errors and -32800 request cancelled errors in Raycast and other MCP clients. Implements lazy authentication with promise caching to prevent concurrent auth attempts and adds graceful startup error handling.
|
|
10
|
+
|
|
11
|
+
## 0.14.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- Upgrade FastMCP dependency from 3.3.1 to 3.18.0
|
|
16
|
+
|
|
17
|
+
- Updated FastMCP to latest version for improved MCP protocol support and performance
|
|
18
|
+
- Added comprehensive CONTRIBUTING.md documentation with release process
|
|
19
|
+
- Improved README documentation structure
|
|
20
|
+
- All existing functionality remains compatible
|
|
21
|
+
|
|
3
22
|
## 0.13.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Contributing to mcp-sunsama
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to the Sunsama MCP Server! This document provides guidelines and instructions for contributing to the project.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository on GitHub
|
|
8
|
+
2. Clone your fork locally:
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/your-username/mcp-sunsama.git
|
|
11
|
+
cd mcp-sunsama
|
|
12
|
+
```
|
|
13
|
+
3. Install dependencies:
|
|
14
|
+
```bash
|
|
15
|
+
bun install
|
|
16
|
+
```
|
|
17
|
+
4. Set up your environment:
|
|
18
|
+
```bash
|
|
19
|
+
cp .env.example .env
|
|
20
|
+
# Edit .env with your Sunsama credentials for testing
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Development Workflow
|
|
24
|
+
|
|
25
|
+
### Branch Naming Convention
|
|
26
|
+
|
|
27
|
+
Use the format `{type}/{short-name}` where `{type}` follows conventional commit naming:
|
|
28
|
+
- `feat/` - New features
|
|
29
|
+
- `fix/` - Bug fixes
|
|
30
|
+
- `chore/` - Maintenance tasks
|
|
31
|
+
- `refactor/` - Code refactoring
|
|
32
|
+
- `docs/` - Documentation updates
|
|
33
|
+
- `test/` - Test additions or fixes
|
|
34
|
+
- `ci/` - CI/CD changes
|
|
35
|
+
|
|
36
|
+
Example: `feat/add-task-labels`
|
|
37
|
+
|
|
38
|
+
### Making Changes
|
|
39
|
+
|
|
40
|
+
1. Create a feature branch from `main`:
|
|
41
|
+
```bash
|
|
42
|
+
git checkout -b feat/your-feature-name
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
2. Make your changes following the code style and conventions
|
|
46
|
+
|
|
47
|
+
3. Run tests and type checking:
|
|
48
|
+
```bash
|
|
49
|
+
bun test
|
|
50
|
+
bun run typecheck
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
4. Build the project to ensure it compiles:
|
|
54
|
+
```bash
|
|
55
|
+
bun run build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
5. Create a changeset for your changes:
|
|
59
|
+
```bash
|
|
60
|
+
bun run changeset
|
|
61
|
+
```
|
|
62
|
+
Follow the prompts to describe your changes.
|
|
63
|
+
|
|
64
|
+
6. Commit your changes using conventional commit format:
|
|
65
|
+
```bash
|
|
66
|
+
git add .
|
|
67
|
+
git commit -m "feat: add support for task labels"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
7. Push your branch and create a pull request
|
|
71
|
+
|
|
72
|
+
## Code Style and Conventions
|
|
73
|
+
|
|
74
|
+
### TypeScript Guidelines
|
|
75
|
+
- Use TypeScript strict mode
|
|
76
|
+
- Prefer explicit types over `any`
|
|
77
|
+
- Use Zod schemas for all tool parameters and responses
|
|
78
|
+
- Follow the existing modular architecture patterns
|
|
79
|
+
|
|
80
|
+
### Architecture Patterns
|
|
81
|
+
- Tools should be organized by resource type (user, task, stream)
|
|
82
|
+
- Use the `createToolWrapper` utility for consistent error handling
|
|
83
|
+
- Apply response optimization (filtering and trimming) for large datasets
|
|
84
|
+
- Follow the dual transport pattern for stdio/httpStream compatibility
|
|
85
|
+
|
|
86
|
+
### Testing
|
|
87
|
+
- Write tests for new Zod schemas in `src/schemas.test.ts`
|
|
88
|
+
- Ensure all existing tests pass before submitting PR
|
|
89
|
+
- Test both stdio and httpStream transports when applicable
|
|
90
|
+
|
|
91
|
+
## Testing Your Changes
|
|
92
|
+
|
|
93
|
+
### Unit Tests
|
|
94
|
+
```bash
|
|
95
|
+
bun test # Run all tests
|
|
96
|
+
bun test:watch # Run tests in watch mode
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Integration Testing
|
|
100
|
+
```bash
|
|
101
|
+
# Test with MCP Inspector
|
|
102
|
+
bun run inspect
|
|
103
|
+
|
|
104
|
+
# Test stdio transport directly
|
|
105
|
+
echo '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"1.0.0","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' | bun src/main.ts
|
|
106
|
+
|
|
107
|
+
# Test compiled output
|
|
108
|
+
bun run build
|
|
109
|
+
node dist/main.js
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Testing with Raycast
|
|
113
|
+
1. Build the project: `bun run build`
|
|
114
|
+
2. Add to Raycast MCP configuration:
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"sunsama-dev": {
|
|
119
|
+
"command": "node",
|
|
120
|
+
"args": ["/path/to/your/mcp-sunsama/dist/main.js"],
|
|
121
|
+
"env": {
|
|
122
|
+
"SUNSAMA_EMAIL": "your-email",
|
|
123
|
+
"SUNSAMA_PASSWORD": "your-password"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
3. Test in Raycast using `@mcp` mentions
|
|
130
|
+
|
|
131
|
+
## For Maintainers
|
|
132
|
+
|
|
133
|
+
### Release Process
|
|
134
|
+
|
|
135
|
+
This project uses [changesets](https://github.com/changesets/changesets) for version management and npm releases.
|
|
136
|
+
|
|
137
|
+
#### Prerequisites
|
|
138
|
+
- npm authentication configured (`npm login`)
|
|
139
|
+
- Write access to the main branch
|
|
140
|
+
- All tests passing on main branch
|
|
141
|
+
|
|
142
|
+
#### Creating a Release
|
|
143
|
+
|
|
144
|
+
1. **Preparation**
|
|
145
|
+
```bash
|
|
146
|
+
git checkout main
|
|
147
|
+
git pull
|
|
148
|
+
bun test # Ensure all tests pass
|
|
149
|
+
bun run typecheck # Check for TypeScript errors
|
|
150
|
+
bun run build # Verify clean build
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
2. **Version Update**
|
|
154
|
+
```bash
|
|
155
|
+
bun run version # Apply changesets and update package.json
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**IMPORTANT**: After running this command, manually update the MCP server version in `src/main.ts` (line ~19) to match the new version in `package.json`:
|
|
159
|
+
```typescript
|
|
160
|
+
const server = new FastMCP({
|
|
161
|
+
name: "Sunsama API Server",
|
|
162
|
+
version: "X.Y.Z", // <-- Update this to match package.json
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
3. **Pre-Release Validation**
|
|
166
|
+
```bash
|
|
167
|
+
bun run typecheck # Ensure no TypeScript errors
|
|
168
|
+
bun test # Verify all tests pass
|
|
169
|
+
bun run build # Ensure clean build
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
4. **Commit Version Changes**
|
|
173
|
+
```bash
|
|
174
|
+
git add .
|
|
175
|
+
git commit -m "chore: release version $(cat package.json | grep '"version"' | cut -d'"' -f4)"
|
|
176
|
+
```
|
|
177
|
+
Verify the commit includes:
|
|
178
|
+
- `package.json` - version bump
|
|
179
|
+
- `CHANGELOG.md` - generated changelog
|
|
180
|
+
- `src/main.ts` - MCP server version update
|
|
181
|
+
- Removed changeset files from `.changeset/`
|
|
182
|
+
|
|
183
|
+
5. **Publish to NPM**
|
|
184
|
+
```bash
|
|
185
|
+
bun run release # Builds and publishes to npm
|
|
186
|
+
```
|
|
187
|
+
This command runs `bun run build && changeset publish`
|
|
188
|
+
|
|
189
|
+
6. **Push Changes**
|
|
190
|
+
```bash
|
|
191
|
+
git push # Push version commit
|
|
192
|
+
git push --tags # Push version tags
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
7. **Verify Release**
|
|
196
|
+
- Check npm: https://www.npmjs.com/package/mcp-sunsama
|
|
197
|
+
- Test installation: `npx mcp-sunsama@latest`
|
|
198
|
+
- Verify GitHub release tag appears
|
|
199
|
+
|
|
200
|
+
#### Version Synchronization
|
|
201
|
+
|
|
202
|
+
The MCP server version in `src/main.ts` must always match the version in `package.json`. This ensures clients receive accurate version information during the MCP handshake.
|
|
203
|
+
|
|
204
|
+
#### Troubleshooting Releases
|
|
205
|
+
|
|
206
|
+
- **npm publish fails**: Check `npm whoami` and ensure you're logged in
|
|
207
|
+
- **Version conflict**: Run `npm view mcp-sunsama versions` to check existing versions
|
|
208
|
+
- **Build fails**: Fix TypeScript/build errors before attempting release
|
|
209
|
+
- **Changeset issues**: Ensure all changesets are committed before running `version`
|
|
210
|
+
|
|
211
|
+
### Dependency Updates
|
|
212
|
+
|
|
213
|
+
When updating dependencies, especially FastMCP:
|
|
214
|
+
1. Update the dependency: `bun add fastmcp@X.Y.Z`
|
|
215
|
+
2. Run full test suite: `bun test`
|
|
216
|
+
3. Test with MCP Inspector: `bun run inspect`
|
|
217
|
+
4. Test stdio transport functionality
|
|
218
|
+
5. Create a changeset describing the update
|
|
219
|
+
|
|
220
|
+
## Questions or Issues?
|
|
221
|
+
|
|
222
|
+
- Open an issue on [GitHub](https://github.com/robertn702/mcp-sunsama/issues)
|
|
223
|
+
- Check existing issues before creating a new one
|
|
224
|
+
- Provide reproduction steps for bugs
|
|
225
|
+
- Include your environment details (OS, Node version, Bun version)
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
By contributing, you agree that your contributions will be licensed under the project's MIT License.
|
package/README.md
CHANGED
|
@@ -128,6 +128,9 @@ bun run typecheck # Run TypeScript type checking
|
|
|
128
128
|
bun run typecheck:watch # Watch mode type checking
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
### Release Process
|
|
132
|
+
For information on creating releases and publishing to npm, see [CONTRIBUTING.md](CONTRIBUTING.md#release-process).
|
|
133
|
+
|
|
131
134
|
### Code Architecture
|
|
132
135
|
|
|
133
136
|
The server is organized with a modular, resource-based architecture:
|
|
@@ -163,10 +166,17 @@ src/
|
|
|
163
166
|
|
|
164
167
|
## Contributing
|
|
165
168
|
|
|
166
|
-
|
|
167
|
-
|
|
169
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:
|
|
170
|
+
- Development workflow
|
|
171
|
+
- Code style and conventions
|
|
172
|
+
- Testing requirements
|
|
173
|
+
- Release process (for maintainers)
|
|
174
|
+
|
|
175
|
+
Quick start:
|
|
176
|
+
1. Fork and clone the repository
|
|
177
|
+
2. Install dependencies: `bun install`
|
|
168
178
|
3. Make your changes
|
|
169
|
-
4.
|
|
179
|
+
4. Create a changeset: `bun run changeset`
|
|
170
180
|
5. Submit a pull request
|
|
171
181
|
|
|
172
182
|
## License
|
package/bun.lock
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"name": "mcp-sunsama",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@types/papaparse": "^5.3.16",
|
|
8
|
-
"fastmcp": "3.
|
|
8
|
+
"fastmcp": "3.18.0",
|
|
9
9
|
"papaparse": "^5.5.3",
|
|
10
10
|
"sunsama-api": "0.11.0",
|
|
11
11
|
"zod": "3.24.4",
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@changesets/cli": "^2.29.
|
|
14
|
+
"@changesets/cli": "^2.29.7",
|
|
15
15
|
"@types/bun": "latest",
|
|
16
16
|
"typescript": "^5",
|
|
17
17
|
},
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"packages": {
|
|
21
21
|
"@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="],
|
|
22
22
|
|
|
23
|
-
"@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.0.
|
|
23
|
+
"@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.0.13", "", { "dependencies": { "@changesets/config": "^3.1.1", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg=="],
|
|
24
24
|
|
|
25
|
-
"@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.
|
|
25
|
+
"@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.9", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ=="],
|
|
26
26
|
|
|
27
27
|
"@changesets/changelog-git": ["@changesets/changelog-git@0.2.1", "", { "dependencies": { "@changesets/types": "^6.1.0" } }, "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q=="],
|
|
28
28
|
|
|
29
|
-
"@changesets/cli": ["@changesets/cli@2.29.
|
|
29
|
+
"@changesets/cli": ["@changesets/cli@2.29.7", "", { "dependencies": { "@changesets/apply-release-plan": "^7.0.13", "@changesets/assemble-release-plan": "^6.0.9", "@changesets/changelog-git": "^0.2.1", "@changesets/config": "^3.1.1", "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/get-release-plan": "^4.0.13", "@changesets/git": "^3.0.4", "@changesets/logger": "^0.1.1", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.5", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@changesets/write": "^0.4.0", "@inquirer/external-editor": "^1.0.0", "@manypkg/get-packages": "^1.1.3", "ansi-colors": "^4.1.3", "ci-info": "^3.7.0", "enquirer": "^2.4.1", "fs-extra": "^7.0.1", "mri": "^1.2.0", "p-limit": "^2.2.0", "package-manager-detector": "^0.2.0", "picocolors": "^1.1.0", "resolve-from": "^5.0.0", "semver": "^7.5.3", "spawndamnit": "^3.0.1", "term-size": "^2.1.0" }, "bin": { "changeset": "bin.js" } }, "sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ=="],
|
|
30
30
|
|
|
31
31
|
"@changesets/config": ["@changesets/config@3.1.1", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/logger": "^0.1.1", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "fs-extra": "^7.0.1", "micromatch": "^4.0.8" } }, "sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA=="],
|
|
32
32
|
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
"@changesets/get-dependents-graph": ["@changesets/get-dependents-graph@2.1.3", "", { "dependencies": { "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "picocolors": "^1.1.0", "semver": "^7.5.3" } }, "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ=="],
|
|
36
36
|
|
|
37
|
-
"@changesets/get-release-plan": ["@changesets/get-release-plan@4.0.
|
|
37
|
+
"@changesets/get-release-plan": ["@changesets/get-release-plan@4.0.13", "", { "dependencies": { "@changesets/assemble-release-plan": "^6.0.9", "@changesets/config": "^3.1.1", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.5", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3" } }, "sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg=="],
|
|
38
38
|
|
|
39
39
|
"@changesets/get-version-range-type": ["@changesets/get-version-range-type@0.4.0", "", {}, "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ=="],
|
|
40
40
|
|
|
@@ -54,13 +54,15 @@
|
|
|
54
54
|
|
|
55
55
|
"@changesets/write": ["@changesets/write@0.4.0", "", { "dependencies": { "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "human-id": "^4.1.1", "prettier": "^2.7.1" } }, "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q=="],
|
|
56
56
|
|
|
57
|
+
"@inquirer/external-editor": ["@inquirer/external-editor@1.0.2", "", { "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ=="],
|
|
58
|
+
|
|
57
59
|
"@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="],
|
|
58
60
|
|
|
59
61
|
"@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="],
|
|
60
62
|
|
|
61
63
|
"@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="],
|
|
62
64
|
|
|
63
|
-
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.
|
|
65
|
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.18.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-beedclIvFcCnPrYgHsylqiYJVJ/CI47Vyc4tY8no1/Li/O8U4BTlJfy6ZwxkYwx+Mx10nrgwSVrA7VBbhh4slg=="],
|
|
64
66
|
|
|
65
67
|
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
|
66
68
|
|
|
@@ -112,7 +114,7 @@
|
|
|
112
114
|
|
|
113
115
|
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
|
114
116
|
|
|
115
|
-
"chardet": ["chardet@
|
|
117
|
+
"chardet": ["chardet@2.1.0", "", {}, "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="],
|
|
116
118
|
|
|
117
119
|
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
|
|
118
120
|
|
|
@@ -174,15 +176,13 @@
|
|
|
174
176
|
|
|
175
177
|
"extendable-error": ["extendable-error@0.1.7", "", {}, "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg=="],
|
|
176
178
|
|
|
177
|
-
"external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="],
|
|
178
|
-
|
|
179
179
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
180
180
|
|
|
181
181
|
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
|
182
182
|
|
|
183
183
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
|
184
184
|
|
|
185
|
-
"fastmcp": ["fastmcp@3.
|
|
185
|
+
"fastmcp": ["fastmcp@3.18.0", "", { "dependencies": { "@modelcontextprotocol/sdk": "^1.17.2", "@standard-schema/spec": "^1.0.0", "execa": "^9.6.0", "file-type": "^21.0.0", "fuse.js": "^7.1.0", "mcp-proxy": "^5.5.4", "strict-event-emitter-types": "^2.0.0", "undici": "^7.13.0", "uri-templates": "^0.2.0", "xsschema": "0.3.5", "yargs": "^18.0.0", "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6" }, "bin": { "fastmcp": "dist/bin/fastmcp.js" } }, "sha512-Td8+QMHmA8WeLTczlMIvV+/Xvk164d/047Hku3kwExuwm3tgMTrwmTI10euP04lNE5WCFZ1xdF9XISnMxeJ3yw=="],
|
|
186
186
|
|
|
187
187
|
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
|
188
188
|
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
|
|
241
241
|
"human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
|
|
242
242
|
|
|
243
|
-
"iconv-lite": ["iconv-lite@0.
|
|
243
|
+
"iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="],
|
|
244
244
|
|
|
245
245
|
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
|
246
246
|
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
|
|
289
289
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
|
290
290
|
|
|
291
|
-
"mcp-proxy": ["mcp-proxy@5.1
|
|
291
|
+
"mcp-proxy": ["mcp-proxy@5.6.1", "", { "bin": { "mcp-proxy": "dist/bin/mcp-proxy.js" } }, "sha512-307KBxoJ4YS4fsa26MFkHLcuWYUoy/bTj/VNG/Km8/elgydEh0o+YpJiG7ywUrHhSsaYKpBc9OgMRxibUCjKKA=="],
|
|
292
292
|
|
|
293
293
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
|
294
294
|
|
|
@@ -318,8 +318,6 @@
|
|
|
318
318
|
|
|
319
319
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
|
320
320
|
|
|
321
|
-
"os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="],
|
|
322
|
-
|
|
323
321
|
"outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="],
|
|
324
322
|
|
|
325
323
|
"p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="],
|
|
@@ -438,8 +436,6 @@
|
|
|
438
436
|
|
|
439
437
|
"tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
|
|
440
438
|
|
|
441
|
-
"tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="],
|
|
442
|
-
|
|
443
439
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
|
444
440
|
|
|
445
441
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
|
@@ -458,7 +454,7 @@
|
|
|
458
454
|
|
|
459
455
|
"uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="],
|
|
460
456
|
|
|
461
|
-
"undici": ["undici@7.
|
|
457
|
+
"undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="],
|
|
462
458
|
|
|
463
459
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
|
464
460
|
|
|
@@ -480,7 +476,7 @@
|
|
|
480
476
|
|
|
481
477
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
482
478
|
|
|
483
|
-
"xsschema": ["xsschema@0.3.
|
|
479
|
+
"xsschema": ["xsschema@0.3.5", "", { "peerDependencies": { "@valibot/to-json-schema": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.16.0", "sury": "^10.0.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "zod", "zod-to-json-schema"] }, "sha512-f+dcy11dTv7aBEEfTbXWnrm/1b/Ds2k4taN0TpN6KCtPAD58kyE/R1znUdrHdBnhIFexj9k+pS1fm6FgtSISrQ=="],
|
|
484
480
|
|
|
485
481
|
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
|
486
482
|
|
|
@@ -494,7 +490,7 @@
|
|
|
494
490
|
|
|
495
491
|
"zod": ["zod@3.24.4", "", {}, "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg=="],
|
|
496
492
|
|
|
497
|
-
"zod-to-json-schema": ["zod-to-json-schema@3.24.
|
|
493
|
+
"zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="],
|
|
498
494
|
|
|
499
495
|
"@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="],
|
|
500
496
|
|
|
@@ -504,18 +500,16 @@
|
|
|
504
500
|
|
|
505
501
|
"@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
|
|
506
502
|
|
|
507
|
-
"@modelcontextprotocol/sdk/zod": ["zod@3.25.
|
|
503
|
+
"@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
|
508
504
|
|
|
509
505
|
"body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
|
510
506
|
|
|
511
507
|
"cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
|
512
508
|
|
|
513
|
-
"fastmcp/zod": ["zod@3.25.
|
|
509
|
+
"fastmcp/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
|
514
510
|
|
|
515
511
|
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
|
516
512
|
|
|
517
|
-
"mcp-proxy/eventsource": ["eventsource@4.0.0", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-fvIkb9qZzdMxgZrEQDyll+9oJsyaVvY92I2Re+qK0qEJ+w5s0X3dtz+M0VAPOjP1gtU3iqWyjQ0G3nvd5CLZ2g=="],
|
|
518
|
-
|
|
519
513
|
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
|
520
514
|
|
|
521
515
|
"raw-body/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
package/dist/auth/stdio.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import { SunsamaClient } from "sunsama-api";
|
|
|
3
3
|
* Initialize stdio authentication using environment variables
|
|
4
4
|
* @throws {Error} If credentials are missing or authentication fails
|
|
5
5
|
*/
|
|
6
|
-
export declare function initializeStdioAuth(): Promise<
|
|
6
|
+
export declare function initializeStdioAuth(): Promise<SunsamaClient>;
|
|
7
7
|
/**
|
|
8
8
|
* Get the global Sunsama client instance for stdio transport
|
|
9
|
-
* @returns {SunsamaClient} The authenticated global client
|
|
10
|
-
* @throws {Error} If
|
|
9
|
+
* @returns {Promise<SunsamaClient>} The authenticated global client
|
|
10
|
+
* @throws {Error} If credentials are missing or authentication fails
|
|
11
11
|
*/
|
|
12
|
-
export declare function getGlobalSunsamaClient(): SunsamaClient
|
|
12
|
+
export declare function getGlobalSunsamaClient(): Promise<SunsamaClient>;
|
|
13
13
|
//# sourceMappingURL=stdio.d.ts.map
|
package/dist/auth/stdio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAWlE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC,CAMrE"}
|
package/dist/auth/stdio.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SunsamaClient } from "sunsama-api";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Cached authentication promise to prevent concurrent auth attempts
|
|
4
4
|
*/
|
|
5
|
-
let
|
|
5
|
+
let authenticationPromise = null;
|
|
6
6
|
/**
|
|
7
7
|
* Initialize stdio authentication using environment variables
|
|
8
8
|
* @throws {Error} If credentials are missing or authentication fails
|
|
@@ -11,17 +11,18 @@ export async function initializeStdioAuth() {
|
|
|
11
11
|
if (!process.env.SUNSAMA_EMAIL || !process.env.SUNSAMA_PASSWORD) {
|
|
12
12
|
throw new Error("Sunsama credentials not configured. Please set SUNSAMA_EMAIL and SUNSAMA_PASSWORD environment variables.");
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
await
|
|
14
|
+
const sunsamaClient = new SunsamaClient();
|
|
15
|
+
await sunsamaClient.login(process.env.SUNSAMA_EMAIL, process.env.SUNSAMA_PASSWORD);
|
|
16
|
+
return sunsamaClient;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
19
|
* Get the global Sunsama client instance for stdio transport
|
|
19
|
-
* @returns {SunsamaClient} The authenticated global client
|
|
20
|
-
* @throws {Error} If
|
|
20
|
+
* @returns {Promise<SunsamaClient>} The authenticated global client
|
|
21
|
+
* @throws {Error} If credentials are missing or authentication fails
|
|
21
22
|
*/
|
|
22
|
-
export function getGlobalSunsamaClient() {
|
|
23
|
-
if (!
|
|
24
|
-
|
|
23
|
+
export async function getGlobalSunsamaClient() {
|
|
24
|
+
if (!authenticationPromise) {
|
|
25
|
+
authenticationPromise = initializeStdioAuth();
|
|
25
26
|
}
|
|
26
|
-
return
|
|
27
|
+
return authenticationPromise;
|
|
27
28
|
}
|
package/dist/main.js
CHANGED
|
@@ -7,13 +7,20 @@ import { allTools } from "./tools/index.js";
|
|
|
7
7
|
import { apiDocumentationResource } from "./resources/index.js";
|
|
8
8
|
// Get transport configuration with validation
|
|
9
9
|
const transportConfig = getTransportConfig();
|
|
10
|
-
// For stdio transport,
|
|
10
|
+
// For stdio transport, attempt authentication at startup with environment variables
|
|
11
11
|
if (transportConfig.transportType === "stdio") {
|
|
12
|
-
|
|
12
|
+
try {
|
|
13
|
+
await initializeStdioAuth();
|
|
14
|
+
console.log("Sunsama authentication successful");
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error("Failed to initialize Sunsama authentication:", error instanceof Error ? error.message : 'Unknown error');
|
|
18
|
+
console.error("Server will start but tools will retry authentication on first use");
|
|
19
|
+
}
|
|
13
20
|
}
|
|
14
21
|
const server = new FastMCP({
|
|
15
22
|
name: "Sunsama API Server",
|
|
16
|
-
version: "0.
|
|
23
|
+
version: "0.14.1",
|
|
17
24
|
instructions: `
|
|
18
25
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
19
26
|
|
package/dist/tools/shared.d.ts
CHANGED
|
@@ -21,10 +21,6 @@ export declare function createToolWrapper<T>(config: {
|
|
|
21
21
|
parameters: any;
|
|
22
22
|
execute: (args: T, context: ToolContext) => Promise<any>;
|
|
23
23
|
};
|
|
24
|
-
/**
|
|
25
|
-
* Gets the Sunsama client for the current session
|
|
26
|
-
*/
|
|
27
|
-
export declare function getClient(session: SessionData | undefined | null): import("sunsama-api").SunsamaClient;
|
|
28
24
|
/**
|
|
29
25
|
* Formats data as JSON response
|
|
30
26
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,GAAG,CAAC;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC1D;;;;oBAKyB,CAAC,WAAW,WAAW;EAchD;AAGD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY,CAS1D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,YAAY,CAS3D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,GAAG,EAAE,EACX,UAAU,EAAE;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GACA,YAAY,CAYd"}
|
package/dist/tools/shared.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
2
1
|
import { toTsv } from "../utils/to-tsv.js";
|
|
3
2
|
/**
|
|
4
3
|
* Creates a standardized tool execution wrapper with error handling and logging
|
|
@@ -24,12 +23,6 @@ export function createToolWrapper(config) {
|
|
|
24
23
|
}
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Gets the Sunsama client for the current session
|
|
29
|
-
*/
|
|
30
|
-
export function getClient(session) {
|
|
31
|
-
return getSunsamaClient(session);
|
|
32
|
-
}
|
|
33
26
|
/**
|
|
34
27
|
* Formats data as JSON response
|
|
35
28
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-tools.d.ts","sourceRoot":"","sources":["../../src/tools/stream-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stream-tools.d.ts","sourceRoot":"","sources":["../../src/tools/stream-tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAErF,eAAO,MAAM,cAAc;;;;;CAczB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;GAAmB,CAAC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { getStreamsSchema } from "../schemas.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
3
|
+
import { createToolWrapper, formatTsvResponse } from "./shared.js";
|
|
3
4
|
export const getStreamsTool = createToolWrapper({
|
|
4
5
|
name: "get-streams",
|
|
5
6
|
description: "Get streams for the user's group (streams are called 'channels' in the Sunsama UI)",
|
|
6
7
|
parameters: getStreamsSchema,
|
|
7
8
|
execute: async (_args, context) => {
|
|
8
9
|
context.log.info("Getting streams for user's group");
|
|
9
|
-
const sunsamaClient =
|
|
10
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
10
11
|
const streams = await sunsamaClient.getStreamsByGroupId();
|
|
11
12
|
context.log.info("Successfully retrieved streams", { count: streams.length });
|
|
12
13
|
return formatTsvResponse(streams);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-tools.d.ts","sourceRoot":"","sources":["../../src/tools/task-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task-tools.d.ts","sourceRoot":"","sources":["../../src/tools/task-tools.ts"],"names":[],"mappings":"AAkCA,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAGrB,eAAO,MAAM,mBAAmB;;;;;CAe9B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;CAkC5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;CAsC/B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;CAqB1B,CAAC;AAGH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;CA4CzB,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;CA2BzB,CAAC;AAGH,eAAO,MAAM,sBAAsB;;;;;;;;;CA4BjC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;CAkCnC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;CAgChC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;CA4BpC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;CAsC9B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;CA6BhC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;CAmC7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;CAiC/B,CAAC;AAGH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoBrB,CAAC"}
|
package/dist/tools/task-tools.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createTaskSchema, deleteTaskSchema, getArchivedTasksSchema, getTaskByIdSchema, getTasksBacklogSchema, getTasksByDaySchema, updateTaskBacklogSchema, updateTaskCompleteSchema, updateTaskDueDateSchema, updateTaskNotesSchema, updateTaskPlannedTimeSchema, updateTaskSnoozeDateSchema, updateTaskStreamSchema, updateTaskTextSchema } from "../schemas.js";
|
|
2
2
|
import { filterTasksByCompletion } from "../utils/task-filters.js";
|
|
3
3
|
import { trimTasksForResponse } from "../utils/task-trimmer.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
5
|
+
import { createToolWrapper, formatJsonResponse, formatTsvResponse, formatPaginatedTsvResponse } from "./shared.js";
|
|
5
6
|
// Task Query Tools
|
|
6
7
|
export const getTasksBacklogTool = createToolWrapper({
|
|
7
8
|
name: "get-tasks-backlog",
|
|
@@ -9,7 +10,7 @@ export const getTasksBacklogTool = createToolWrapper({
|
|
|
9
10
|
parameters: getTasksBacklogSchema,
|
|
10
11
|
execute: async (_args, context) => {
|
|
11
12
|
context.log.info("Getting backlog tasks");
|
|
12
|
-
const sunsamaClient =
|
|
13
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
13
14
|
const tasks = await sunsamaClient.getTasksBacklog();
|
|
14
15
|
const trimmedTasks = trimTasksForResponse(tasks);
|
|
15
16
|
context.log.info("Successfully retrieved backlog tasks", { count: tasks.length });
|
|
@@ -26,7 +27,7 @@ export const getTasksByDayTool = createToolWrapper({
|
|
|
26
27
|
timezone,
|
|
27
28
|
completionFilter
|
|
28
29
|
});
|
|
29
|
-
const sunsamaClient =
|
|
30
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
30
31
|
// If no timezone provided, get the user's default timezone
|
|
31
32
|
let resolvedTimezone = timezone;
|
|
32
33
|
if (!resolvedTimezone) {
|
|
@@ -58,7 +59,7 @@ export const getArchivedTasksTool = createToolWrapper({
|
|
|
58
59
|
requestedLimit,
|
|
59
60
|
fetchLimit
|
|
60
61
|
});
|
|
61
|
-
const sunsamaClient =
|
|
62
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
62
63
|
const allTasks = await sunsamaClient.getArchivedTasks(offset, fetchLimit);
|
|
63
64
|
const hasMore = allTasks.length > requestedLimit;
|
|
64
65
|
const tasks = hasMore ? allTasks.slice(0, requestedLimit) : allTasks;
|
|
@@ -85,7 +86,7 @@ export const getTaskByIdTool = createToolWrapper({
|
|
|
85
86
|
parameters: getTaskByIdSchema,
|
|
86
87
|
execute: async ({ taskId }, context) => {
|
|
87
88
|
context.log.info("Getting task by ID", { taskId });
|
|
88
|
-
const sunsamaClient =
|
|
89
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
89
90
|
const task = await sunsamaClient.getTaskById(taskId);
|
|
90
91
|
if (task) {
|
|
91
92
|
context.log.info("Successfully retrieved task by ID", {
|
|
@@ -116,7 +117,7 @@ export const createTaskTool = createToolWrapper({
|
|
|
116
117
|
isPrivate: isPrivate,
|
|
117
118
|
customTaskId: !!taskId
|
|
118
119
|
});
|
|
119
|
-
const sunsamaClient =
|
|
120
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
120
121
|
const options = {};
|
|
121
122
|
if (notes)
|
|
122
123
|
options.notes = notes;
|
|
@@ -157,7 +158,7 @@ export const deleteTaskTool = createToolWrapper({
|
|
|
157
158
|
limitResponsePayload,
|
|
158
159
|
wasTaskMerged
|
|
159
160
|
});
|
|
160
|
-
const sunsamaClient =
|
|
161
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
161
162
|
const result = await sunsamaClient.deleteTask(taskId, limitResponsePayload, wasTaskMerged);
|
|
162
163
|
context.log.info("Successfully deleted task", {
|
|
163
164
|
taskId,
|
|
@@ -182,7 +183,7 @@ export const updateTaskCompleteTool = createToolWrapper({
|
|
|
182
183
|
hasCustomCompleteOn: !!completeOn,
|
|
183
184
|
limitResponsePayload
|
|
184
185
|
});
|
|
185
|
-
const sunsamaClient =
|
|
186
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
186
187
|
const result = await sunsamaClient.updateTaskComplete(taskId, completeOn, limitResponsePayload);
|
|
187
188
|
context.log.info("Successfully marked task as complete", {
|
|
188
189
|
taskId,
|
|
@@ -208,7 +209,7 @@ export const updateTaskSnoozeDateTool = createToolWrapper({
|
|
|
208
209
|
timezone,
|
|
209
210
|
limitResponsePayload
|
|
210
211
|
});
|
|
211
|
-
const sunsamaClient =
|
|
212
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
212
213
|
const options = {};
|
|
213
214
|
if (timezone)
|
|
214
215
|
options.timezone = timezone;
|
|
@@ -238,7 +239,7 @@ export const updateTaskBacklogTool = createToolWrapper({
|
|
|
238
239
|
timezone,
|
|
239
240
|
limitResponsePayload
|
|
240
241
|
});
|
|
241
|
-
const sunsamaClient =
|
|
242
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
242
243
|
const options = {};
|
|
243
244
|
if (timezone)
|
|
244
245
|
options.timezone = timezone;
|
|
@@ -267,7 +268,7 @@ export const updateTaskPlannedTimeTool = createToolWrapper({
|
|
|
267
268
|
timeEstimateMinutes,
|
|
268
269
|
limitResponsePayload
|
|
269
270
|
});
|
|
270
|
-
const sunsamaClient =
|
|
271
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
271
272
|
const result = await sunsamaClient.updateTaskPlannedTime(taskId, timeEstimateMinutes, limitResponsePayload);
|
|
272
273
|
context.log.info("Successfully updated task planned time", {
|
|
273
274
|
taskId,
|
|
@@ -296,7 +297,7 @@ export const updateTaskNotesTool = createToolWrapper({
|
|
|
296
297
|
contentLength: content.value.length,
|
|
297
298
|
limitResponsePayload
|
|
298
299
|
});
|
|
299
|
-
const sunsamaClient =
|
|
300
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
300
301
|
const options = {};
|
|
301
302
|
if (limitResponsePayload !== undefined)
|
|
302
303
|
options.limitResponsePayload = limitResponsePayload;
|
|
@@ -325,7 +326,7 @@ export const updateTaskDueDateTool = createToolWrapper({
|
|
|
325
326
|
dueDate,
|
|
326
327
|
limitResponsePayload
|
|
327
328
|
});
|
|
328
|
-
const sunsamaClient =
|
|
329
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
329
330
|
const result = await sunsamaClient.updateTaskDueDate(taskId, dueDate, limitResponsePayload);
|
|
330
331
|
context.log.info("Successfully updated task due date", {
|
|
331
332
|
taskId,
|
|
@@ -352,7 +353,7 @@ export const updateTaskTextTool = createToolWrapper({
|
|
|
352
353
|
recommendedStreamId,
|
|
353
354
|
limitResponsePayload
|
|
354
355
|
});
|
|
355
|
-
const sunsamaClient =
|
|
356
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
356
357
|
const options = {};
|
|
357
358
|
if (recommendedStreamId !== undefined)
|
|
358
359
|
options.recommendedStreamId = recommendedStreamId;
|
|
@@ -383,7 +384,7 @@ export const updateTaskStreamTool = createToolWrapper({
|
|
|
383
384
|
streamId,
|
|
384
385
|
limitResponsePayload
|
|
385
386
|
});
|
|
386
|
-
const sunsamaClient =
|
|
387
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
387
388
|
const result = await sunsamaClient.updateTaskStream(taskId, streamId, limitResponsePayload !== undefined ? limitResponsePayload : true);
|
|
388
389
|
context.log.info("Successfully updated task stream assignment", {
|
|
389
390
|
taskId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-tools.d.ts","sourceRoot":"","sources":["../../src/tools/user-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"user-tools.d.ts","sourceRoot":"","sources":["../../src/tools/user-tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtF,eAAO,MAAM,WAAW;;;;;CActB,CAAC;AAEH,eAAO,MAAM,SAAS;;;;;GAAgB,CAAC"}
|
package/dist/tools/user-tools.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { getUserSchema } from "../schemas.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
3
|
+
import { createToolWrapper, formatJsonResponse } from "./shared.js";
|
|
3
4
|
export const getUserTool = createToolWrapper({
|
|
4
5
|
name: "get-user",
|
|
5
6
|
description: "Get current user information including profile, timezone, and group details",
|
|
6
7
|
parameters: getUserSchema,
|
|
7
8
|
execute: async (_args, context) => {
|
|
8
9
|
context.log.info("Getting user information");
|
|
9
|
-
const sunsamaClient =
|
|
10
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
10
11
|
const user = await sunsamaClient.getUser();
|
|
11
12
|
context.log.info("Successfully retrieved user information", { userId: user._id });
|
|
12
13
|
return formatJsonResponse(user);
|
|
@@ -2,9 +2,9 @@ import { SunsamaClient } from "sunsama-api";
|
|
|
2
2
|
import type { SessionData } from "../auth/types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Gets the appropriate SunsamaClient instance based on transport type
|
|
5
|
-
* @param session - Session data for HTTP transport (null for stdio)
|
|
6
|
-
* @returns Authenticated SunsamaClient instance
|
|
5
|
+
* @param session - Session data for HTTP transport (undefined/null for stdio)
|
|
6
|
+
* @returns Promise<SunsamaClient> Authenticated SunsamaClient instance
|
|
7
7
|
* @throws {Error} If session is not available for HTTP transport or global client not initialized for stdio
|
|
8
8
|
*/
|
|
9
|
-
export declare function getSunsamaClient(session
|
|
9
|
+
export declare function getSunsamaClient(session?: SessionData | null): Promise<SunsamaClient>;
|
|
10
10
|
//# sourceMappingURL=client-resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;GAKG;AACH,
|
|
1
|
+
{"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAW3F"}
|
|
@@ -3,11 +3,11 @@ import { getGlobalSunsamaClient } from "../auth/stdio.js";
|
|
|
3
3
|
import { getTransportConfig } from "../config/transport.js";
|
|
4
4
|
/**
|
|
5
5
|
* Gets the appropriate SunsamaClient instance based on transport type
|
|
6
|
-
* @param session - Session data for HTTP transport (null for stdio)
|
|
7
|
-
* @returns Authenticated SunsamaClient instance
|
|
6
|
+
* @param session - Session data for HTTP transport (undefined/null for stdio)
|
|
7
|
+
* @returns Promise<SunsamaClient> Authenticated SunsamaClient instance
|
|
8
8
|
* @throws {Error} If session is not available for HTTP transport or global client not initialized for stdio
|
|
9
9
|
*/
|
|
10
|
-
export function getSunsamaClient(session) {
|
|
10
|
+
export async function getSunsamaClient(session) {
|
|
11
11
|
const transportConfig = getTransportConfig();
|
|
12
12
|
if (transportConfig.transportType === "httpStream") {
|
|
13
13
|
if (!session?.sunsamaClient) {
|
|
@@ -15,5 +15,5 @@ export function getSunsamaClient(session) {
|
|
|
15
15
|
}
|
|
16
16
|
return session.sunsamaClient;
|
|
17
17
|
}
|
|
18
|
-
return getGlobalSunsamaClient();
|
|
18
|
+
return await getGlobalSunsamaClient();
|
|
19
19
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-sunsama",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "MCP server for Sunsama API integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@types/papaparse": "^5.3.16",
|
|
27
|
-
"fastmcp": "3.
|
|
27
|
+
"fastmcp": "3.18.0",
|
|
28
28
|
"papaparse": "^5.5.3",
|
|
29
29
|
"sunsama-api": "0.11.0",
|
|
30
30
|
"zod": "3.24.4"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@changesets/cli": "^2.29.
|
|
33
|
+
"@changesets/cli": "^2.29.7",
|
|
34
34
|
"@types/bun": "latest",
|
|
35
35
|
"typescript": "^5"
|
|
36
36
|
},
|
package/src/auth/stdio.ts
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import { SunsamaClient } from "sunsama-api";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Cached authentication promise to prevent concurrent auth attempts
|
|
5
5
|
*/
|
|
6
|
-
let
|
|
6
|
+
let authenticationPromise: Promise<SunsamaClient> | null = null;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Initialize stdio authentication using environment variables
|
|
10
10
|
* @throws {Error} If credentials are missing or authentication fails
|
|
11
11
|
*/
|
|
12
|
-
export async function initializeStdioAuth(): Promise<
|
|
12
|
+
export async function initializeStdioAuth(): Promise<SunsamaClient> {
|
|
13
13
|
if (!process.env.SUNSAMA_EMAIL || !process.env.SUNSAMA_PASSWORD) {
|
|
14
14
|
throw new Error(
|
|
15
15
|
"Sunsama credentials not configured. Please set SUNSAMA_EMAIL and SUNSAMA_PASSWORD environment variables."
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
await
|
|
19
|
+
const sunsamaClient = new SunsamaClient();
|
|
20
|
+
await sunsamaClient.login(process.env.SUNSAMA_EMAIL, process.env.SUNSAMA_PASSWORD);
|
|
21
|
+
|
|
22
|
+
return sunsamaClient;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Get the global Sunsama client instance for stdio transport
|
|
25
|
-
* @returns {SunsamaClient} The authenticated global client
|
|
26
|
-
* @throws {Error} If
|
|
27
|
+
* @returns {Promise<SunsamaClient>} The authenticated global client
|
|
28
|
+
* @throws {Error} If credentials are missing or authentication fails
|
|
27
29
|
*/
|
|
28
|
-
export function getGlobalSunsamaClient(): SunsamaClient {
|
|
29
|
-
if (!
|
|
30
|
-
|
|
30
|
+
export async function getGlobalSunsamaClient(): Promise<SunsamaClient> {
|
|
31
|
+
if (!authenticationPromise) {
|
|
32
|
+
authenticationPromise = initializeStdioAuth();
|
|
31
33
|
}
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
return authenticationPromise;
|
|
33
36
|
}
|
package/src/main.ts
CHANGED
|
@@ -9,14 +9,20 @@ import { apiDocumentationResource } from "./resources/index.js";
|
|
|
9
9
|
// Get transport configuration with validation
|
|
10
10
|
const transportConfig = getTransportConfig();
|
|
11
11
|
|
|
12
|
-
// For stdio transport,
|
|
12
|
+
// For stdio transport, attempt authentication at startup with environment variables
|
|
13
13
|
if (transportConfig.transportType === "stdio") {
|
|
14
|
-
|
|
14
|
+
try {
|
|
15
|
+
await initializeStdioAuth();
|
|
16
|
+
console.log("Sunsama authentication successful");
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error("Failed to initialize Sunsama authentication:", error instanceof Error ? error.message : 'Unknown error');
|
|
19
|
+
console.error("Server will start but tools will retry authentication on first use");
|
|
20
|
+
}
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
const server = new FastMCP({
|
|
18
24
|
name: "Sunsama API Server",
|
|
19
|
-
version: "0.
|
|
25
|
+
version: "0.14.1",
|
|
20
26
|
instructions: `
|
|
21
27
|
This MCP server provides access to the Sunsama API for task and project management.
|
|
22
28
|
|
package/src/tools/shared.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Context } from "fastmcp";
|
|
2
2
|
import type { SessionData } from "../auth/types.js";
|
|
3
|
-
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
4
3
|
import { toTsv } from "../utils/to-tsv.js";
|
|
5
4
|
|
|
6
5
|
export type ToolContext = Context<SessionData>;
|
|
@@ -41,12 +40,6 @@ export function createToolWrapper<T>(config: {
|
|
|
41
40
|
};
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* Gets the Sunsama client for the current session
|
|
46
|
-
*/
|
|
47
|
-
export function getClient(session: SessionData | undefined | null) {
|
|
48
|
-
return getSunsamaClient(session as SessionData | null);
|
|
49
|
-
}
|
|
50
43
|
|
|
51
44
|
/**
|
|
52
45
|
* Formats data as JSON response
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getStreamsSchema, type GetStreamsInput } from "../schemas.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
3
|
+
import { createToolWrapper, formatTsvResponse, type ToolContext } from "./shared.js";
|
|
3
4
|
|
|
4
5
|
export const getStreamsTool = createToolWrapper({
|
|
5
6
|
name: "get-streams",
|
|
@@ -8,7 +9,7 @@ export const getStreamsTool = createToolWrapper({
|
|
|
8
9
|
execute: async (_args: GetStreamsInput, context: ToolContext) => {
|
|
9
10
|
context.log.info("Getting streams for user's group");
|
|
10
11
|
|
|
11
|
-
const sunsamaClient =
|
|
12
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
12
13
|
const streams = await sunsamaClient.getStreamsByGroupId();
|
|
13
14
|
|
|
14
15
|
context.log.info("Successfully retrieved streams", { count: streams.length });
|
package/src/tools/task-tools.ts
CHANGED
|
@@ -31,9 +31,9 @@ import {
|
|
|
31
31
|
} from "../schemas.js";
|
|
32
32
|
import { filterTasksByCompletion } from "../utils/task-filters.js";
|
|
33
33
|
import { trimTasksForResponse } from "../utils/task-trimmer.js";
|
|
34
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
34
35
|
import {
|
|
35
36
|
createToolWrapper,
|
|
36
|
-
getClient,
|
|
37
37
|
formatJsonResponse,
|
|
38
38
|
formatTsvResponse,
|
|
39
39
|
formatPaginatedTsvResponse,
|
|
@@ -48,7 +48,7 @@ export const getTasksBacklogTool = createToolWrapper({
|
|
|
48
48
|
execute: async (_args: GetTasksBacklogInput, context: ToolContext) => {
|
|
49
49
|
context.log.info("Getting backlog tasks");
|
|
50
50
|
|
|
51
|
-
const sunsamaClient =
|
|
51
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
52
52
|
const tasks = await sunsamaClient.getTasksBacklog();
|
|
53
53
|
const trimmedTasks = trimTasksForResponse(tasks);
|
|
54
54
|
|
|
@@ -69,7 +69,7 @@ export const getTasksByDayTool = createToolWrapper({
|
|
|
69
69
|
completionFilter
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
const sunsamaClient =
|
|
72
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
73
73
|
|
|
74
74
|
// If no timezone provided, get the user's default timezone
|
|
75
75
|
let resolvedTimezone = timezone;
|
|
@@ -108,7 +108,7 @@ export const getArchivedTasksTool = createToolWrapper({
|
|
|
108
108
|
fetchLimit
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
const sunsamaClient =
|
|
111
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
112
112
|
const allTasks = await sunsamaClient.getArchivedTasks(offset, fetchLimit);
|
|
113
113
|
|
|
114
114
|
const hasMore = allTasks.length > requestedLimit;
|
|
@@ -141,7 +141,7 @@ export const getTaskByIdTool = createToolWrapper({
|
|
|
141
141
|
execute: async ({ taskId }: GetTaskByIdInput, context: ToolContext) => {
|
|
142
142
|
context.log.info("Getting task by ID", { taskId });
|
|
143
143
|
|
|
144
|
-
const sunsamaClient =
|
|
144
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
145
145
|
const task = await sunsamaClient.getTaskById(taskId);
|
|
146
146
|
|
|
147
147
|
if (task) {
|
|
@@ -175,7 +175,7 @@ export const createTaskTool = createToolWrapper({
|
|
|
175
175
|
customTaskId: !!taskId
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
const sunsamaClient =
|
|
178
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
179
179
|
|
|
180
180
|
const options: CreateTaskOptions = {};
|
|
181
181
|
if (notes) options.notes = notes;
|
|
@@ -216,7 +216,7 @@ export const deleteTaskTool = createToolWrapper({
|
|
|
216
216
|
wasTaskMerged
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
const sunsamaClient =
|
|
219
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
220
220
|
const result = await sunsamaClient.deleteTask(taskId, limitResponsePayload, wasTaskMerged);
|
|
221
221
|
|
|
222
222
|
context.log.info("Successfully deleted task", {
|
|
@@ -246,7 +246,7 @@ export const updateTaskCompleteTool = createToolWrapper({
|
|
|
246
246
|
limitResponsePayload
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
-
const sunsamaClient =
|
|
249
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
250
250
|
const result = await sunsamaClient.updateTaskComplete(taskId, completeOn, limitResponsePayload);
|
|
251
251
|
|
|
252
252
|
context.log.info("Successfully marked task as complete", {
|
|
@@ -277,7 +277,7 @@ export const updateTaskSnoozeDateTool = createToolWrapper({
|
|
|
277
277
|
limitResponsePayload
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
const sunsamaClient =
|
|
280
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
281
281
|
|
|
282
282
|
const options: { timezone?: string; limitResponsePayload?: boolean } = {};
|
|
283
283
|
if (timezone) options.timezone = timezone;
|
|
@@ -312,7 +312,7 @@ export const updateTaskBacklogTool = createToolWrapper({
|
|
|
312
312
|
limitResponsePayload
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
-
const sunsamaClient =
|
|
315
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
316
316
|
|
|
317
317
|
const options: { timezone?: string; limitResponsePayload?: boolean } = {};
|
|
318
318
|
if (timezone) options.timezone = timezone;
|
|
@@ -346,7 +346,7 @@ export const updateTaskPlannedTimeTool = createToolWrapper({
|
|
|
346
346
|
limitResponsePayload
|
|
347
347
|
});
|
|
348
348
|
|
|
349
|
-
const sunsamaClient =
|
|
349
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
350
350
|
const result = await sunsamaClient.updateTaskPlannedTime(taskId, timeEstimateMinutes, limitResponsePayload);
|
|
351
351
|
|
|
352
352
|
context.log.info("Successfully updated task planned time", {
|
|
@@ -381,7 +381,7 @@ export const updateTaskNotesTool = createToolWrapper({
|
|
|
381
381
|
limitResponsePayload
|
|
382
382
|
});
|
|
383
383
|
|
|
384
|
-
const sunsamaClient =
|
|
384
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
385
385
|
|
|
386
386
|
const options: { limitResponsePayload?: boolean } = {};
|
|
387
387
|
if (limitResponsePayload !== undefined) options.limitResponsePayload = limitResponsePayload;
|
|
@@ -416,7 +416,7 @@ export const updateTaskDueDateTool = createToolWrapper({
|
|
|
416
416
|
limitResponsePayload
|
|
417
417
|
});
|
|
418
418
|
|
|
419
|
-
const sunsamaClient =
|
|
419
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
420
420
|
const result = await sunsamaClient.updateTaskDueDate(taskId, dueDate, limitResponsePayload);
|
|
421
421
|
|
|
422
422
|
context.log.info("Successfully updated task due date", {
|
|
@@ -448,7 +448,7 @@ export const updateTaskTextTool = createToolWrapper({
|
|
|
448
448
|
limitResponsePayload
|
|
449
449
|
});
|
|
450
450
|
|
|
451
|
-
const sunsamaClient =
|
|
451
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
452
452
|
|
|
453
453
|
const options: { recommendedStreamId?: string | null; limitResponsePayload?: boolean } = {};
|
|
454
454
|
if (recommendedStreamId !== undefined) options.recommendedStreamId = recommendedStreamId;
|
|
@@ -484,7 +484,7 @@ export const updateTaskStreamTool = createToolWrapper({
|
|
|
484
484
|
limitResponsePayload
|
|
485
485
|
});
|
|
486
486
|
|
|
487
|
-
const sunsamaClient =
|
|
487
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
488
488
|
const result = await sunsamaClient.updateTaskStream(
|
|
489
489
|
taskId,
|
|
490
490
|
streamId,
|
package/src/tools/user-tools.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getUserSchema, type GetUserInput } from "../schemas.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getSunsamaClient } from "../utils/client-resolver.js";
|
|
3
|
+
import { createToolWrapper, formatJsonResponse, type ToolContext } from "./shared.js";
|
|
3
4
|
|
|
4
5
|
export const getUserTool = createToolWrapper({
|
|
5
6
|
name: "get-user",
|
|
@@ -8,7 +9,7 @@ export const getUserTool = createToolWrapper({
|
|
|
8
9
|
execute: async (_args: GetUserInput, context: ToolContext) => {
|
|
9
10
|
context.log.info("Getting user information");
|
|
10
11
|
|
|
11
|
-
const sunsamaClient =
|
|
12
|
+
const sunsamaClient = await getSunsamaClient(context.session);
|
|
12
13
|
const user = await sunsamaClient.getUser();
|
|
13
14
|
|
|
14
15
|
context.log.info("Successfully retrieved user information", { userId: user._id });
|
|
@@ -5,19 +5,19 @@ import { getTransportConfig } from "../config/transport.js";
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Gets the appropriate SunsamaClient instance based on transport type
|
|
8
|
-
* @param session - Session data for HTTP transport (null for stdio)
|
|
9
|
-
* @returns Authenticated SunsamaClient instance
|
|
8
|
+
* @param session - Session data for HTTP transport (undefined/null for stdio)
|
|
9
|
+
* @returns Promise<SunsamaClient> Authenticated SunsamaClient instance
|
|
10
10
|
* @throws {Error} If session is not available for HTTP transport or global client not initialized for stdio
|
|
11
11
|
*/
|
|
12
|
-
export function getSunsamaClient(session
|
|
12
|
+
export async function getSunsamaClient(session?: SessionData | null): Promise<SunsamaClient> {
|
|
13
13
|
const transportConfig = getTransportConfig();
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
if (transportConfig.transportType === "httpStream") {
|
|
16
16
|
if (!session?.sunsamaClient) {
|
|
17
17
|
throw new Error("Session not available. Authentication may have failed.");
|
|
18
18
|
}
|
|
19
19
|
return session.sunsamaClient;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
return getGlobalSunsamaClient();
|
|
21
|
+
|
|
22
|
+
return await getGlobalSunsamaClient();
|
|
23
23
|
}
|