🚀 Hello World
This commit is contained in:
commit
0172c07623
48 changed files with 11896 additions and 0 deletions
131
.eslintrc.json
Normal file
131
.eslintrc.json
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"env": {
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"prettier",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript"
|
||||
],
|
||||
"plugins": ["@typescript-eslint", "import", "prettier", "simple-import-sort"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ignorePatterns": ["dist/*", "node_modules/*", "*.js"],
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
// Enables eslint-import-resolver-typescript
|
||||
"typescript": {}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": "warn",
|
||||
// Require all external imports to be declared as a dependency
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{
|
||||
"packageDir": "./"
|
||||
}
|
||||
],
|
||||
// Imports must not cause cyclical dependencies
|
||||
"import/no-cycle": [
|
||||
"error",
|
||||
{ "allowUnsafeDynamicCyclicDependency": true }
|
||||
],
|
||||
"import/no-named-as-default-member": "off",
|
||||
// Imports must be ordered appropriately
|
||||
"simple-import-sort/imports": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
// Side effect imports.
|
||||
["^\\u0000"],
|
||||
// Node.js builtins prefixed with `node:`.
|
||||
["^node:"],
|
||||
// Packages.
|
||||
// Things that start with a letter (or digit or underscore), or `@` followed by a letter.
|
||||
["^@?\\w"],
|
||||
// Absolute imports
|
||||
["^@/"],
|
||||
// Relative imports.
|
||||
// Anything that starts with a dot.
|
||||
["^\\."]
|
||||
]
|
||||
}
|
||||
],
|
||||
"simple-import-sort/exports": "error",
|
||||
// Imports must be placed before non-import statements
|
||||
"import/first": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-duplicates": "error",
|
||||
|
||||
// Require a space at the start of comments
|
||||
"spaced-comment": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"markers": ["/"]
|
||||
}
|
||||
],
|
||||
|
||||
// Make sure switch-case doesn't accidentally fall-through https://eslint.org/docs/latest/rules/no-fallthrough
|
||||
"no-fallthrough": "error",
|
||||
|
||||
"@typescript-eslint/ban-ts-comment": "warn",
|
||||
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
"prefer": "type-imports"
|
||||
}
|
||||
],
|
||||
|
||||
// Disallow annotating types where the type can be easily inferred
|
||||
"@typescript-eslint/no-inferrable-types": [
|
||||
"error",
|
||||
{
|
||||
"ignoreParameters": false,
|
||||
"ignoreProperties": false
|
||||
}
|
||||
],
|
||||
// Allow non-null assertions
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
// Disallow using 'any' explicitly in annotations
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
// Require promise outcomes to be properly handled
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
// Turn off base eslint rule in favor of typescript-eslint version
|
||||
// to avoid getting eslint errors on type signatures
|
||||
"no-unused-vars": "off",
|
||||
// Disallow unused variables and imports
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"args": "after-used",
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true,
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"destructuredArrayIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
|
||||
// Disallow empty functions
|
||||
// If a function is intentionally empty, adding a comment line
|
||||
// inside the function body is enough to pass this rule
|
||||
"@typescript-eslint/no-empty-function": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["test/**/*.ts"],
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.test.json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
108
.gitignore
vendored
Normal file
108
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
.DS_Store
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Webpack
|
||||
.webpack/
|
||||
|
||||
# Claude files
|
||||
.claude.json
|
||||
.claude/
|
||||
|
||||
# Vite
|
||||
.vite/
|
||||
|
||||
# Electron-Forge
|
||||
out/
|
||||
_out/
|
||||
|
||||
# Sentry auth token
|
||||
.env.sentry-build-plugin
|
||||
|
||||
# Dynamically-generated resources
|
||||
dist
|
||||
self-signed-cert.pem
|
||||
self-signed-key.pem
|
||||
*.dxt
|
||||
invalid-json.json
|
||||
**/server/lib/**
|
||||
1
.npmignore
Normal file
1
.npmignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
!MANIFEST.md
|
||||
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": ["typescript"],
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
305
CLI.md
Normal file
305
CLI.md
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
# DXT CLI Documentation
|
||||
|
||||
The DXT CLI provides tools for building Desktop Extensions.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install -g @anthropic-ai/dxt
|
||||
```
|
||||
|
||||
```
|
||||
Usage: dxt [options] [command]
|
||||
|
||||
Tools for building Desktop Extensions
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
-h, --help display help for command
|
||||
|
||||
Commands:
|
||||
init [directory] Create a new DXT extension manifest
|
||||
validate <manifest> Validate a DXT manifest file
|
||||
pack <directory> [output] Pack a directory into a DXT extension
|
||||
sign [options] <dxt-file> Sign a DXT extension file
|
||||
verify <dxt-file> Verify the signature of a DXT extension file
|
||||
info <dxt-file> Display information about a DXT extension file
|
||||
unsign <dxt-file> Remove signature from a DXT extension file
|
||||
help [command] display help for command
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### `dxt init [directory]`
|
||||
|
||||
Creates a new DXT extension manifest interactively.
|
||||
|
||||
```bash
|
||||
# Initialize in current directory
|
||||
dxt init
|
||||
|
||||
# Initialize in a specific directory
|
||||
dxt init my-extension/
|
||||
```
|
||||
|
||||
The command will prompt you for:
|
||||
|
||||
- Extension name (defaults from package.json or folder name)
|
||||
- Author name (defaults from package.json)
|
||||
- Extension ID (auto-generated from author and extension name)
|
||||
- Display name
|
||||
- Version (defaults from package.json or 1.0.0)
|
||||
- Description
|
||||
- Author email and URL (optional)
|
||||
- Server type (Node.js, Python, or Binary)
|
||||
- Entry point (with sensible defaults per server type)
|
||||
- Tools configuration
|
||||
- Keywords, license, and repository information
|
||||
|
||||
After creating the manifest, it provides helpful next steps based on your server type.
|
||||
|
||||
### `dxt validate <path>`
|
||||
|
||||
Validates a DXT manifest file against the schema. You can provide either a direct path to a manifest.json file or a directory containing one.
|
||||
|
||||
```bash
|
||||
# Validate specific manifest file
|
||||
dxt validate manifest.json
|
||||
|
||||
# Validate manifest in directory
|
||||
dxt validate ./my-extension
|
||||
dxt validate .
|
||||
```
|
||||
|
||||
### `dxt pack <directory> [output]`
|
||||
|
||||
Packs a directory into a DXT extension file.
|
||||
|
||||
```bash
|
||||
# Pack current directory into extension.dxt
|
||||
dxt pack .
|
||||
|
||||
# Pack with custom output filename
|
||||
dxt pack my-extension/ my-extension-v1.0.dxt
|
||||
```
|
||||
|
||||
The command automatically:
|
||||
|
||||
- Validates the manifest.json
|
||||
- Excludes common development files (.git, node_modules/.cache, .DS_Store, etc.)
|
||||
- Creates a compressed .dxt file (ZIP with maximum compression)
|
||||
|
||||
### `dxt sign <dxt-file>`
|
||||
|
||||
Signs a DXT extension file with a certificate.
|
||||
|
||||
```bash
|
||||
# Sign with default certificate paths
|
||||
dxt sign my-extension.dxt
|
||||
|
||||
# Sign with custom certificate and key
|
||||
dxt sign my-extension.dxt --cert /path/to/cert.pem --key /path/to/key.pem
|
||||
|
||||
# Sign with intermediate certificates
|
||||
dxt sign my-extension.dxt --cert cert.pem --key key.pem --intermediate intermediate1.pem intermediate2.pem
|
||||
|
||||
# Create and use a self-signed certificate
|
||||
dxt sign my-extension.dxt --self-signed
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `--cert, -c`: Path to certificate file (PEM format, default: cert.pem)
|
||||
- `--key, -k`: Path to private key file (PEM format, default: key.pem)
|
||||
- `--intermediate, -i`: Paths to intermediate certificate files
|
||||
- `--self-signed`: Create a self-signed certificate if none exists
|
||||
|
||||
### `dxt verify <dxt-file>`
|
||||
|
||||
Verifies the signature of a signed DXT extension file.
|
||||
|
||||
```bash
|
||||
dxt verify my-extension.dxt
|
||||
```
|
||||
|
||||
Output includes:
|
||||
|
||||
- Signature validity status
|
||||
- Certificate subject and issuer
|
||||
- Certificate validity dates
|
||||
- Certificate fingerprint
|
||||
- Warning if self-signed
|
||||
|
||||
### `dxt info <dxt-file>`
|
||||
|
||||
Displays information about a DXT extension file.
|
||||
|
||||
```bash
|
||||
dxt info my-extension.dxt
|
||||
```
|
||||
|
||||
Shows:
|
||||
|
||||
- File size
|
||||
- Signature status
|
||||
- Certificate details (if signed)
|
||||
|
||||
### `dxt unsign <dxt-file>`
|
||||
|
||||
Removes the signature from a DXT extension file (for development/testing).
|
||||
|
||||
```bash
|
||||
dxt unsign my-extension.dxt
|
||||
```
|
||||
|
||||
## Certificate Requirements
|
||||
|
||||
For signing extensions, you need:
|
||||
|
||||
1. **Certificate**: X.509 certificate in PEM format
|
||||
|
||||
- Should have Code Signing extended key usage
|
||||
- Can be self-signed (for development) or CA-issued (for production)
|
||||
|
||||
2. **Private Key**: Corresponding private key in PEM format
|
||||
|
||||
- Must match the certificate's public key
|
||||
|
||||
3. **Intermediate Certificates** (optional): For CA-issued certificates
|
||||
- Required for proper certificate chain validation
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Quick Start with Init
|
||||
|
||||
```bash
|
||||
# 1. Create a new extension directory
|
||||
mkdir my-awesome-extension
|
||||
cd my-awesome-extension
|
||||
|
||||
# 2. Initialize the extension
|
||||
dxt init
|
||||
|
||||
# 3. Follow the prompts to configure your extension
|
||||
# The tool will create a manifest.json with all necessary fields
|
||||
|
||||
# 4. Create your server implementation based on the entry point you specified
|
||||
|
||||
# 5. Pack the extension
|
||||
dxt pack .
|
||||
|
||||
# 6. (Optional) Sign the extension
|
||||
dxt sign my-awesome-extension.dxt --self-signed
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
|
||||
```bash
|
||||
# 1. Create your extension
|
||||
mkdir my-extension
|
||||
cd my-extension
|
||||
|
||||
# 2. Initialize with dxt init or create manifest.json manually
|
||||
dxt init
|
||||
|
||||
# 3. Implement your server
|
||||
# For Node.js: create server/index.js
|
||||
# For Python: create server/main.py
|
||||
# For Binary: add your executable
|
||||
|
||||
# 4. Validate manifest
|
||||
dxt validate manifest.json
|
||||
|
||||
# 5. Pack extension
|
||||
dxt pack . my-extension.dxt
|
||||
|
||||
# 6. (Optional) Sign for testing
|
||||
dxt sign my-extension.dxt --self-signed
|
||||
|
||||
# 7. Verify signature
|
||||
dxt verify my-extension.dxt
|
||||
|
||||
# 8. Check extension info
|
||||
dxt info my-extension.dxt
|
||||
```
|
||||
|
||||
### Production Workflow
|
||||
|
||||
```bash
|
||||
# 1. Pack your extension
|
||||
dxt pack my-extension/
|
||||
|
||||
# 2. Sign with production certificate
|
||||
dxt sign my-extension.dxt \
|
||||
--cert production-cert.pem \
|
||||
--key production-key.pem \
|
||||
--intermediate intermediate-ca.pem root-ca.pem
|
||||
|
||||
# 3. Verify before distribution
|
||||
dxt verify my-extension.dxt
|
||||
```
|
||||
|
||||
## Excluded Files
|
||||
|
||||
When packing an extension, the following files/patterns are automatically excluded:
|
||||
|
||||
- `.DS_Store`, `Thumbs.db`
|
||||
- `.gitignore`, `.git/`
|
||||
- `*.log`, `npm-debug.log*`, `yarn-debug.log*`, `yarn-error.log*`
|
||||
- `.npm/`, `.npmrc`, `.yarnrc`, `.yarn/`, `.pnp.*`
|
||||
- `node_modules/.cache/`, `node_modules/.bin/`
|
||||
- `*.map`
|
||||
- `.env.local`, `.env.*.local`
|
||||
- `package-lock.json`, `yarn.lock`
|
||||
|
||||
### Custom Exclusions with .dxtignore
|
||||
|
||||
You can create a `.dxtignore` file in your extension directory to specify additional files and patterns to exclude during packing. This works similar to `.npmignore` or `.gitignore`:
|
||||
|
||||
```
|
||||
# .dxtignore example
|
||||
# Comments start with #
|
||||
*.test.js
|
||||
src/**/*.test.ts
|
||||
coverage/
|
||||
*.log
|
||||
.env*
|
||||
temp/
|
||||
docs/
|
||||
```
|
||||
|
||||
The `.dxtignore` file supports:
|
||||
|
||||
- **Exact matches**: `filename.txt`
|
||||
- **Simple globs**: `*.log`, `temp/*`
|
||||
- **Directory paths**: `docs/`, `coverage/`
|
||||
- **Comments**: Lines starting with `#` are ignored
|
||||
- **Empty lines**: Blank lines are ignored
|
||||
|
||||
When a `.dxtignore` file is found, the CLI will display the number of additional patterns being applied. These patterns are combined with the default exclusion list.
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Signature Format
|
||||
|
||||
DXT uses PKCS#7 (Cryptographic Message Syntax) for digital signatures:
|
||||
|
||||
- Signatures are stored in DER-encoded PKCS#7 SignedData format
|
||||
- The signature is appended to the DXT file with markers (`DXT_SIG_V1` and `DXT_SIG_END`)
|
||||
- The entire DXT content (excluding the signature block) is signed
|
||||
- Detached signature format - the original ZIP content remains unmodified
|
||||
|
||||
### Signature Structure
|
||||
|
||||
```
|
||||
[Original DXT ZIP content]
|
||||
DXT_SIG_V1
|
||||
[Base64-encoded PKCS#7 signature]
|
||||
DXT_SIG_END
|
||||
```
|
||||
|
||||
This approach allows:
|
||||
|
||||
- Backward compatibility (unsigned DXT files are valid ZIP files)
|
||||
- Easy signature verification and removal
|
||||
- Support for certificate chains with intermediate certificates
|
||||
7
LICENSE.md
Normal file
7
LICENSE.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Copyright 2025 Anthropic, PBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
608
MANIFEST.md
Normal file
608
MANIFEST.md
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
# DXT Manifest.json Spec
|
||||
|
||||
Current version: `0.1`
|
||||
Last updated: 2025-06-17
|
||||
|
||||
## Manifest Schema
|
||||
|
||||
The `manifest.json` file contains all extension metadata and configuration. Most fields are optional.
|
||||
|
||||
A basic `manifest.json` with just the required fields looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"dxt_version": "0.1", // DXT spec version this manifest conforms to
|
||||
"name": "my-extension", // Machine-readable name (used for CLI, APIs)
|
||||
"version": "1.0.0", // Semantic version of your extension
|
||||
"description": "A simple MCP extension", // Brief description of what the extension does
|
||||
"author": {
|
||||
// Author information (required)
|
||||
"name": "Extension Author" // Author's name (required field)
|
||||
},
|
||||
"server": {
|
||||
// Server configuration (required)
|
||||
"type": "node", // Server type: "node", "python", or "binary"
|
||||
"entry_point": "server/index.js", // Path to the main server file
|
||||
"mcp_config": {
|
||||
// MCP server configuration
|
||||
"command": "node", // Command to run the server
|
||||
"args": [
|
||||
// Arguments passed to the command
|
||||
"${__dirname}/server/index.js" // ${__dirname} is replaced with the extension's directory
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"dxt_version": "0.1",
|
||||
"name": "my-extension",
|
||||
"version": "1.0.0",
|
||||
"description": "A simple MCP extension",
|
||||
"author": {
|
||||
"name": "Extension Author"
|
||||
},
|
||||
"server": {
|
||||
"type": "node",
|
||||
"entry_point": "server/index.js",
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": ["${__dirname}/server/index.js"],
|
||||
"env": {
|
||||
"API_KEY": "${user_config.api_key}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_config": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"title": "API Key",
|
||||
"description": "Your API key for authentication",
|
||||
"sensitive": true,
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A full `manifest.json` with most of the optional fields looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"dxt_version": "0.1",
|
||||
"name": "My MCP Extension",
|
||||
"display_name": "My Awesome MCP Extension",
|
||||
"version": "1.0.0",
|
||||
"description": "A brief description of what this extension does",
|
||||
"long_description": "A detailed description that can include multiple paragraphs explaining the extension's functionality, use cases, and features. It supports basic markdown.",
|
||||
"author": {
|
||||
"name": "Your Name",
|
||||
"email": "yourname@example.com",
|
||||
"url": "https://your-website.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/your-username/my-mcp-extension"
|
||||
},
|
||||
"homepage": "https://example.com/my-extension",
|
||||
"documentation": "https://docs.example.com/my-extension",
|
||||
"support": "https://github.com/your-username/my-extension/issues",
|
||||
"icon": "icon.png",
|
||||
"screenshots": [
|
||||
"assets/screenshots/screenshot1.png",
|
||||
"assets/screenshots/screenshot2.png"
|
||||
],
|
||||
"server": {
|
||||
"type": "node",
|
||||
"entry_point": "server/index.js",
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": ["server/index.js"],
|
||||
"env": {
|
||||
"ALLOWED_DIRECTORIES": "${user_config.allowed_directories}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"name": "search_files",
|
||||
"description": "Search for files in a directory"
|
||||
}
|
||||
],
|
||||
"prompts": [
|
||||
{
|
||||
"name": "poetry",
|
||||
"description": "Have the LLM write poetry",
|
||||
"arguments": ["topic"],
|
||||
"text": "Write a creative poem about the following topic: ${arguments.topic}"
|
||||
}
|
||||
],
|
||||
"tools_generated": true,
|
||||
"keywords": ["api", "automation", "productivity"],
|
||||
"license": "MIT",
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=1.0.0",
|
||||
"platforms": ["darwin", "win32", "linux"],
|
||||
"runtimes": {
|
||||
"python": ">=3.8",
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"user_config": {
|
||||
"allowed_directories": {
|
||||
"type": "directory",
|
||||
"title": "Allowed Directories",
|
||||
"description": "Directories the server can access",
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"default": ["${HOME}/Desktop"]
|
||||
},
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"title": "API Key",
|
||||
"description": "Your API key for authentication",
|
||||
"sensitive": true,
|
||||
"required": false
|
||||
},
|
||||
"max_file_size": {
|
||||
"type": "number",
|
||||
"title": "Maximum File Size (MB)",
|
||||
"description": "Maximum file size to process",
|
||||
"default": 10,
|
||||
"min": 1,
|
||||
"max": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Field Definitions
|
||||
|
||||
### Required Fields
|
||||
|
||||
- **dxt_version**: Specification version this extension conforms to
|
||||
- **name**: Machine-readable name (used for CLI, APIs)
|
||||
- **version**: Semantic version (semver)
|
||||
- **description**: Brief description
|
||||
- **author**: Author information object with name (required), email (optional), and url (optional)
|
||||
- **server**: Server configuration object
|
||||
|
||||
### Optional Fields
|
||||
|
||||
- **icon**: Path to a png icon file, either relative in the package or a https:// url.
|
||||
- **display_name**: Human-friendly name for UI display
|
||||
- **long_description**: Detailed description for extension stores, markdown
|
||||
- **repository**: Source code repository information (type and url)
|
||||
- **homepage**: Extension homepage URL
|
||||
- **documentation**: Documentation URL
|
||||
- **support**: Support/issues URL
|
||||
- **screenshots**: Array of screenshot paths
|
||||
- **tools**: Array of tools the extension provides
|
||||
- **tools_generated**: Boolean indicating the server generates additional tools at runtime (default: false)
|
||||
- **prompts**: Array of prompts the extension provides
|
||||
- **prompts_generated**: Boolean indicating the server generates additional prompts at runtime (default: false)
|
||||
- **keywords**: Search keywords
|
||||
- **license**: License identifier
|
||||
- **compatibility**: Compatibility requirements (client app version, platforms, and runtime versions)
|
||||
- **user_config**: User-configurable options for the extension (see User Configuration section)
|
||||
|
||||
## Compatibility
|
||||
|
||||
The `compatibility` object specifies all requirements for running the extension. All fields, including the `compatibility` field itself, are optional. If you specify nothing, clients implementing DXT are encouraged to run the extension on any system.
|
||||
|
||||
```json
|
||||
{
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=1.0.0",
|
||||
"my_client": ">1.0.0",
|
||||
"other_client": ">=2.0.0 <3.0.0",
|
||||
"platforms": ["darwin", "win32", "linux"],
|
||||
"runtimes": {
|
||||
"python": ">=3.8",
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fields
|
||||
|
||||
#### Client Version Constraints
|
||||
|
||||
The compatibility object supports version constraints for any client application:
|
||||
|
||||
- **claude_desktop**: Minimum Claude Desktop version required (uses semver)
|
||||
- **my_client**: Version constraint for a custom client (uses semver)
|
||||
- **Other client names**: You can add version constraints for any client application
|
||||
|
||||
All client version constraints use semver syntax (e.g., `">=1.0.0"`, `">1.0.0 <2.0.0"`, `"^1.2.3"`).
|
||||
|
||||
#### System Requirements
|
||||
|
||||
- **platforms**: Array of supported platforms (`darwin`, `win32`, `linux`). These match Node.js `process.platform` and Python's `sys.platform` values. If omitted, all platforms are supported
|
||||
- **runtimes**: Runtime version requirements
|
||||
- Only specify the runtime(s) your extension actually uses
|
||||
- For Python extensions: specify `python` version
|
||||
- For Node.js extensions: specify `node` version
|
||||
- Binary extensions don't need runtime specifications
|
||||
|
||||
**Note**: Use `darwin` for macOS, `win32` for Windows, and `linux` for Linux systems
|
||||
|
||||
### Examples
|
||||
|
||||
**Python Extension:**
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"type": "python",
|
||||
"entry_point": "server/main.py"
|
||||
},
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=0.10.0",
|
||||
"platforms": ["darwin", "win32", "linux"],
|
||||
"runtimes": {
|
||||
"python": ">=3.8,<4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Node.js Extension that only supports macOS:**
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"type": "node",
|
||||
"entry_point": "server/index.js"
|
||||
},
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=0.10.0",
|
||||
"platforms": ["darwin"],
|
||||
"runtimes": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Binary Extension (no runtime needed):**
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"type": "binary",
|
||||
"entry_point": "server/my-tool"
|
||||
},
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=0.10.0",
|
||||
"platforms": ["darwin", "win32"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Server Configuration
|
||||
|
||||
The `server` object defines how to run the MCP server:
|
||||
|
||||
### Server Types
|
||||
|
||||
1. **Python**: `server.type = "python"`
|
||||
|
||||
- Requires `entry_point` to Python file
|
||||
- All dependencies must be bundled in the DXT
|
||||
- Can use `server/lib` for packages or `server/venv` for full virtual environment
|
||||
- Python runtime version specified in `compatibility.runtimes.python`
|
||||
|
||||
2. **Node.js**: `server.type = "node"`
|
||||
|
||||
- Requires `entry_point` to JavaScript file
|
||||
- All dependencies must be bundled in `node_modules`
|
||||
- Node.js runtime version specified in `compatibility.runtimes.node`
|
||||
- Typically includes `package.json` at extension root for dependency management
|
||||
|
||||
3. **Binary**: `server.type = "binary"`
|
||||
- Pre-compiled executable with all dependencies included
|
||||
- Platform-specific binaries supported
|
||||
- Completely self-contained (no runtime requirements)
|
||||
|
||||
### MCP Configuration
|
||||
|
||||
The `mcp_config` object in the server configuration defines how the implementing app should execute the MCP server. This replaces the manual JSON configuration users currently need to write.
|
||||
|
||||
**Python Example:**
|
||||
|
||||
```json
|
||||
"mcp_config": {
|
||||
"command": "python",
|
||||
"args": ["server/main.py"],
|
||||
"env": {
|
||||
"PYTHONPATH": "server/lib"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Node.js Example:**
|
||||
|
||||
```json
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": ["${__dirname}/server/index.js"],
|
||||
"env": {}
|
||||
}
|
||||
```
|
||||
|
||||
**Binary Example (Cross-Platform):**
|
||||
|
||||
```json
|
||||
"mcp_config": {
|
||||
"command": "server/my-server",
|
||||
"args": ["--config", "server/config.json"],
|
||||
"env": {}
|
||||
}
|
||||
```
|
||||
|
||||
_Note: For binaries, apps will automatically append `.exe` on Windows_
|
||||
|
||||
**Platform-Specific Configurations:**
|
||||
For cases where different platforms need different configurations, use platform-specific overrides:
|
||||
|
||||
```json
|
||||
"mcp_config": {
|
||||
"command": "server/my-server",
|
||||
"args": ["--config", "server/config.json"],
|
||||
"env": {},
|
||||
"platform_overrides": {
|
||||
"win32": {
|
||||
"command": "server/my-server.exe",
|
||||
"args": ["--config", "server/config-windows.json"]
|
||||
},
|
||||
"darwin": {
|
||||
"env": {
|
||||
"DYLD_LIBRARY_PATH": "server/lib"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When installing the extension, apps will automatically generate the appropriate MCP server configuration and add it to the user's settings, eliminating the need for manual JSON editing.
|
||||
|
||||
**Variable Substitution:**
|
||||
The implementing desktop app will substitute variables in the `mcp_config` to make extensions more portable:
|
||||
|
||||
- **`${__dirname}`**: This variable is replaced with the absolute path to the extension's directory. This is useful for referencing files within the extension package.
|
||||
- **`${HOME}`**: User's home directory
|
||||
- **`${DESKTOP}`**: User's desktop directory
|
||||
- **`${DOCUMENTS}`**: User's documents directory
|
||||
- **`${DOWNLOADS}`**: User's downloads directory
|
||||
- **`${pathSeparator}`** or **`${/}`**: Path separator for the current platform
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"mcp_config": {
|
||||
"command": "python",
|
||||
"args": ["${__dirname}/server/main.py"],
|
||||
"env": {
|
||||
"CONFIG_PATH": "${__dirname}/config/settings.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This ensures that paths work correctly regardless of where the extension is installed on the user's system.
|
||||
|
||||
- **`${user_config}`**: Your extension can specify user-configured values that the implementing app will collect from users. Read on to learn more about user configuration.
|
||||
|
||||
## User Configuration
|
||||
|
||||
The `user_config` field allows extension developers to specify configuration options that can be presented to end users through the implementing app's user interface. These configurations are collected from users and passed to the MCP server at runtime.
|
||||
|
||||
### Configuration Schema
|
||||
|
||||
Each configuration option is defined as a key-value pair where the key is the configuration name and the value is an object with these properties:
|
||||
|
||||
- **type**: The data type of the configuration
|
||||
- `"string"`: Text input
|
||||
- `"number"`: Numeric input
|
||||
- `"boolean"`: Checkbox/toggle
|
||||
- `"directory"`: Directory picker
|
||||
- `"file"`: File picker
|
||||
- **title**: Display name shown in the UI
|
||||
- **description**: Help text explaining the configuration option
|
||||
- **required**: Whether this field must be provided (default: false)
|
||||
- **default**: Default value (supports variable substitution)
|
||||
- **multiple**: For directory/file types, allow multiple selections (default: false)
|
||||
- **sensitive**: For string types, mask input and store securely (default: false)
|
||||
- **min/max**: For number types, validation constraints
|
||||
|
||||
### Variable Substitution in User Configuration
|
||||
|
||||
User configuration values support variable substitution in `mcp_config`:
|
||||
|
||||
- **`${user_config.KEY}`**: Replaced with the user-provided value for configuration KEY
|
||||
- Arrays (from multiple selections) are expanded as separate arguments
|
||||
- Environment variables are ideal for sensitive data
|
||||
- Command arguments work well for paths and non-sensitive options
|
||||
|
||||
Available variables for default values:
|
||||
|
||||
- **`${HOME}`**: User's home directory
|
||||
- **`${DESKTOP}`**: User's desktop directory
|
||||
- **`${DOCUMENTS}`**: User's documents directory
|
||||
|
||||
### Examples
|
||||
|
||||
**Filesystem Extension with Directory Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"user_config": {
|
||||
"allowed_directories": {
|
||||
"type": "directory",
|
||||
"title": "Allowed Directories",
|
||||
"description": "Select directories the filesystem server can access",
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"default": ["${HOME}/Desktop", "${HOME}/Documents"]
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"${__dirname}/server/index.js",
|
||||
"${user_config.allowed_directories}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**API Integration with Authentication:**
|
||||
|
||||
```json
|
||||
{
|
||||
"user_config": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"title": "API Key",
|
||||
"description": "Your API key for authentication",
|
||||
"sensitive": true,
|
||||
"required": true
|
||||
},
|
||||
"base_url": {
|
||||
"type": "string",
|
||||
"title": "API Base URL",
|
||||
"description": "The base URL for API requests",
|
||||
"default": "https://api.example.com",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": ["server/index.js"],
|
||||
"env": {
|
||||
"API_KEY": "${user_config.api_key}",
|
||||
"BASE_URL": "${user_config.base_url}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Database Connection Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"user_config": {
|
||||
"database_path": {
|
||||
"type": "file",
|
||||
"title": "Database File",
|
||||
"description": "Path to your SQLite database file",
|
||||
"required": true
|
||||
},
|
||||
"read_only": {
|
||||
"type": "boolean",
|
||||
"title": "Read Only Mode",
|
||||
"description": "Open database in read-only mode",
|
||||
"default": true
|
||||
},
|
||||
"timeout": {
|
||||
"type": "number",
|
||||
"title": "Query Timeout (seconds)",
|
||||
"description": "Maximum time for query execution",
|
||||
"default": 30,
|
||||
"min": 1,
|
||||
"max": 300
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"mcp_config": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"server/main.py",
|
||||
"--database",
|
||||
"${user_config.database_path}",
|
||||
"--timeout",
|
||||
"${user_config.timeout}"
|
||||
],
|
||||
"env": {
|
||||
"READ_ONLY": "${user_config.read_only}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- **Array Expansion**: When a configuration with `multiple: true` is used in `args`, each value is expanded as a separate argument. For example, if the user selects directories `/home/user/docs` and `/home/user/projects`, the args `["${user_config.allowed_directories}"]` becomes `["/home/user/docs", "/home/user/projects"]`.
|
||||
|
||||
## Tools and Prompts
|
||||
|
||||
These fields describe the tools and prompts your MCP server provides. For servers that generate capabilities dynamically at runtime, you can use the `_generated` flags to indicate this.
|
||||
|
||||
Note: Resources are not included in the manifest because MCP resources are inherently dynamic - they represent URIs to data that the server discovers at runtime based on configuration, filesystem state, database connections, etc.
|
||||
|
||||
### Static Declaration
|
||||
|
||||
For servers with a fixed set of capabilities, list them in arrays.
|
||||
|
||||
#### Prompt Structure
|
||||
|
||||
Each prompt in the `prompts` array must include:
|
||||
|
||||
- **name**: The identifier for the prompt
|
||||
- **description** (optional): Explanation of what the prompt does
|
||||
- **arguments** (optional): Array of argument names that can be used in the prompt text
|
||||
- **text**: The actual prompt text that uses template variables like `${arguments.topic}` or `${arguments.aspect}` as placeholders for MCP Client-supplied arguments. If your argument is named `language`, you'd add `${arguments.language} where you expect it to show up in the prompt.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": [
|
||||
{ "name": "search_files", "description": "Search for files" },
|
||||
{ "name": "read_file", "description": "Read file contents" }
|
||||
],
|
||||
"prompts": [
|
||||
{
|
||||
"name": "explain_code",
|
||||
"description": "Explain how code works",
|
||||
"arguments": ["code", "language"],
|
||||
"text": "Please explain the following ${arguments.language} code in detail:\n\n${arguments.code}"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Implementing apps may choose to validate prompts at run-time against the declaration of your prompts in the manifest.
|
||||
|
||||
### Dynamic Generation
|
||||
|
||||
For servers that generate capabilities based on context, configuration, or runtime discovery, use the `_generated` flags:
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": [{ "name": "search", "description": "Search functionality" }],
|
||||
"tools_generated": true,
|
||||
"prompts_generated": true
|
||||
}
|
||||
```
|
||||
|
||||
This indicates that:
|
||||
|
||||
- The server provides at least the `search` tool (and possibly more)
|
||||
- Additional tools are generated at runtime
|
||||
- Prompts are generated at runtime
|
||||
|
||||
The `_generated` fields:
|
||||
|
||||
- **tools_generated**: Server generates additional tools beyond those listed (default: false)
|
||||
- **prompts_generated**: Server generates additional prompts beyond those listed (default: false)
|
||||
|
||||
This helps implementing apps understand that querying the server at runtime will reveal more capabilities than what's declared in the manifest.
|
||||
118
README.md
Normal file
118
README.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Desktop Extensions (DXT)
|
||||
|
||||
Desktop Extensions (`.dxt`) are zip archives containing a local MCP server and a `manifest.json` that describes the server and its capabilities. The format is spiritually similar to Chrome extensions (`.crx`) or VS Code extensions (`.vsix`), enabling end users to install local MCP servers with a single click.
|
||||
|
||||
This repository provides three components: The extension specification in [MANIFEST.md](MANIFEST.md), a CLI tool for creating extensions (see [CLI.md](CLI.md)), and the code used by Claude for macOS and Windows to load and verify DXT extensions ([src/index.ts](src/index.ts)).
|
||||
|
||||
- For developers of local MCP servers, we aim to make distribution and installation of said servers convenient
|
||||
- For developers of apps supporting local MCP servers, we aim to make it easy to add support for DXT extensions
|
||||
|
||||
Claude for macOS and Windows uses the code in this repository to enable single-click installation of local MCP servers, including a number of end user-friendly features - such as automatic updates, easy configuration of MCP servers and the variables and parameters they need, and a curated directory. We are committed to the open ecosystem around MCP servers and believe that its ability to be universally adopted by multiple applications and services has benefits developers aiming to connect AI tools to other apps and services. Consequently, we’re open-sourcing the Desktop Extension specification, toolchain, and the schemas and key functions used by Claude for macOS and Windows to implement its own support of Desktop Extensions. It is our hope that the `dxt` format doesn’t just make local MCP servers more portable for Claude, but other AI desktop applications, too.
|
||||
|
||||
# For Extension Developers
|
||||
|
||||
At the core, DXT are simple zip files containing your entire MCP server and a `manifest.json`. Consequently, turning a local MCP server into an extension is straightforward: You just have to put all your required files in a folder, create a `manifest.json`, and then create an archive.
|
||||
|
||||
To make this process easier, this package offers a CLI that helps you with the creation of both the `manifest.json` and the final `.dxt` file. To install it, run:
|
||||
|
||||
```sh
|
||||
npm install -g @anthropic-ai/dxt
|
||||
```
|
||||
|
||||
1. In a folder containing your local MCP server, run `dxt init`. This command will guide you through the creation of a `manifest.json`.
|
||||
2. Run `dxt pack` to create a `dxt` file.
|
||||
3. Now, any app implementing support for DXT can run your local MCP server. As an example, open the file with Claude for macOS and Windows to show an installation dialog.
|
||||
|
||||
You can find the full spec for the `manifest.json` and all its mandatory and optional fields in [MANIFEST.md](MANIFEST.md). Examples for extensions can be found in [examples](./examples/).
|
||||
|
||||
## Prompt Template for AI Tools
|
||||
|
||||
AI tools like Claude Code are particularly good at creating desktop extensions when informed about the spec. When prompting an AI coding tool to build an extension, briefly explain what your extension aims to do - then add the following context to your instructions.
|
||||
|
||||
> I want to build this as a Desktop Extension, abbreviated as "DXT". Please follow these steps:
|
||||
>
|
||||
> 1. **Read the specifications thoroughly:**
|
||||
> - https://github.com/anthropics/dxt/blob/main/README.md - DXT architecture overview, capabilities, and integration
|
||||
> patterns
|
||||
> - https://github.com/anthropics/dxt/blob/main/MANIFEST.md - Complete extension manifest structure and field definitions
|
||||
> - https://github.com/anthropics/dxt/tree/main/examples - Reference implementations including a "Hello World" example
|
||||
> 2. **Create a proper extension structure:**
|
||||
> - Generate a valid manifest.json following the MANIFEST.md spec
|
||||
> - Implement an MCP server using @modelcontextprotocol/sdk with proper tool definitions
|
||||
> - Include proper error handling, security measures, and timeout management
|
||||
> 3. **Follow best development practices:**
|
||||
> - Implement proper MCP protocol communication via stdio transport
|
||||
> - Structure tools with clear schemas, validation, and consistent JSON responses
|
||||
> - Make use of the fact that this extension will be running locally
|
||||
> - Add appropriate logging and debugging capabilities
|
||||
> - Include proper documentation and setup instructions
|
||||
> 4. **Test considerations:**
|
||||
> - Validate that all tool calls return properly structured responses
|
||||
> - Verify manifest loads correctly and host integration works
|
||||
>
|
||||
> Generate complete, production-ready code that can be immediately tested. Focus on defensive programming, clear error messages, and following the exact DXT specifications to ensure compatibility with the ecosystem.
|
||||
|
||||
## Directory Structures
|
||||
|
||||
### Minimal Extension
|
||||
|
||||
A `manifest.json` is the only required file.
|
||||
|
||||
### Example: Node.js Extension
|
||||
|
||||
```
|
||||
extension.dxt (ZIP file)
|
||||
├── manifest.json # Required: Extension metadata and configuration
|
||||
├── server/ # Server files
|
||||
│ └── index.js # Main entry point
|
||||
├── node_modules/ # Bundled dependencies
|
||||
├── package.json # Optional: NPM package definition
|
||||
├── icon.png # Optional: Extension icon
|
||||
└── assets/ # Optional: Additional assets
|
||||
```
|
||||
|
||||
### Example: Python Extension
|
||||
|
||||
```
|
||||
extension.dxt (ZIP file)
|
||||
├── manifest.json # Required: Extension metadata and configuration
|
||||
├── server/ # Server files
|
||||
│ ├── main.py # Main entry point
|
||||
│ └── utils.py # Additional modules
|
||||
├── lib/ # Bundled Python packages
|
||||
├── requirements.txt # Optional: Python dependencies list
|
||||
└── icon.png # Optional: Extension icon
|
||||
```
|
||||
|
||||
### Example: Binary Extension
|
||||
|
||||
```
|
||||
extension.dxt (ZIP file)
|
||||
├── manifest.json # Required: Extension metadata and configuration
|
||||
├── server/ # Server files
|
||||
│ ├── my-server # Unix executable
|
||||
│ ├── my-server.exe # Windows executable
|
||||
└── icon.png # Optional: Extension icon
|
||||
```
|
||||
|
||||
### Bundling Dependencies
|
||||
|
||||
**Python Extensions:**
|
||||
|
||||
- Bundle all required packages in `server/lib/` directory
|
||||
- OR bundle a complete virtual environment in `server/venv/`
|
||||
- Use tools like `pip-tools`, `poetry`, or `pipenv` to create reproducible bundles
|
||||
- Set `PYTHONPATH` to include bundled packages via `mcp_config.env`
|
||||
|
||||
**Node.js Extensions:**
|
||||
|
||||
- Run `npm install --production` to create `node_modules`
|
||||
- Bundle the entire `node_modules` directory with your extension
|
||||
- Use `npm ci` or `yarn install --frozen-lockfile` for reproducible builds
|
||||
- Server entry point specified in manifest.json's `server.entry_point`
|
||||
|
||||
**Binary Extensions:**
|
||||
|
||||
- Static linking preferred for maximum compatibility
|
||||
- Include all required shared libraries if dynamic linking used
|
||||
- Test on clean systems without development tools
|
||||
73
examples/chrome-applescript/manifest.json
Normal file
73
examples/chrome-applescript/manifest.json
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"dxt_version": "0.1",
|
||||
"name": "chrome-applescript",
|
||||
"display_name": "Control Chrome with AppleScript",
|
||||
"version": "0.1.0",
|
||||
"description": "Control Google Chrome browser tabs, windows, and navigation",
|
||||
"long_description": "This extension allows you to control Google Chrome browser tabs, windows, and navigation through Chrome's official AppleScript API. You can open URLs, manage tabs, execute JavaScript, and retrieve page content.\n\nThis extension is meant to be a demonstration of Desktop Extensions.\n\nThis extension is not affiliated with Google or Chrome.",
|
||||
"author": {
|
||||
"name": "Anthropic",
|
||||
"email": "support@anthropic.com",
|
||||
"url": "https://github.com/anthropics"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server/index.js",
|
||||
"build": "npx @anthropic-ai/dxt pack"
|
||||
},
|
||||
"server": {
|
||||
"type": "node",
|
||||
"entry_point": "server/index.js",
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": ["${__dirname}/server/index.js"],
|
||||
"env": {}
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"name": "open_url",
|
||||
"description": "Open a URL in Chrome, either in a new tab or current tab."
|
||||
},
|
||||
{
|
||||
"name": "get_current_tab",
|
||||
"description": "Get information about the current active tab."
|
||||
},
|
||||
{
|
||||
"name": "list_tabs",
|
||||
"description": "List all open tabs in Chrome."
|
||||
},
|
||||
{
|
||||
"name": "close_tab",
|
||||
"description": "Close a specific tab."
|
||||
},
|
||||
{
|
||||
"name": "switch_to_tab",
|
||||
"description": "Switch to a specific tab."
|
||||
},
|
||||
{
|
||||
"name": "reload_tab",
|
||||
"description": "Reload a tab."
|
||||
},
|
||||
{
|
||||
"name": "go_back",
|
||||
"description": "Navigate back in browser history."
|
||||
},
|
||||
{
|
||||
"name": "go_forward",
|
||||
"description": "Navigate forward in browser history."
|
||||
},
|
||||
{
|
||||
"name": "execute_javascript",
|
||||
"description": "Execute JavaScript in the current tab."
|
||||
},
|
||||
{
|
||||
"name": "get_page_content",
|
||||
"description": "Get the text content of the current page."
|
||||
}
|
||||
],
|
||||
"compatibility": {
|
||||
"platforms": ["darwin"]
|
||||
},
|
||||
"keywords": ["chrome", "browser", "remote"],
|
||||
"license": "MIT"
|
||||
}
|
||||
784
examples/chrome-applescript/server/index.js
Normal file
784
examples/chrome-applescript/server/index.js
Normal file
|
|
@ -0,0 +1,784 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import { execFile } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
// Constants
|
||||
const APPLESCRIPT_TIMEOUT = 10000; // 10 seconds
|
||||
const MAX_RETRIES = 3;
|
||||
const RETRY_DELAY = 1000; // 1 second
|
||||
|
||||
class ChromeControlServer {
|
||||
constructor() {
|
||||
this.server = new Server(
|
||||
{
|
||||
name: "chrome-applescript",
|
||||
version: "0.1.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
this.setupHandlers();
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
escapeForAppleScript(str) {
|
||||
if (typeof str !== "string") return str;
|
||||
// Basic AppleScript string escaping
|
||||
return str
|
||||
.replace(/\\/g, "\\\\") // Escape backslashes first
|
||||
.replace(/"/g, '\\"') // Then escape double quotes
|
||||
.replace(/\n/g, "\\n") // Escape newlines
|
||||
.replace(/\r/g, "\\r"); // Escape carriage returns
|
||||
}
|
||||
|
||||
async checkChromeAvailable() {
|
||||
try {
|
||||
const script = 'tell application "Google Chrome" to return "available"';
|
||||
const result = await this.executeAppleScript(script);
|
||||
return result === "available";
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async executeAppleScript(script, retries = MAX_RETRIES) {
|
||||
for (let attempt = 0; attempt <= retries; attempt++) {
|
||||
try {
|
||||
const { stdout, stderr } = await execFileAsync(
|
||||
"osascript",
|
||||
["-e", script],
|
||||
{
|
||||
timeout: APPLESCRIPT_TIMEOUT,
|
||||
maxBuffer: 1024 * 1024, // 1MB buffer
|
||||
},
|
||||
);
|
||||
if (stderr) {
|
||||
console.error("AppleScript stderr:", stderr);
|
||||
}
|
||||
return stdout.trim();
|
||||
} catch (error) {
|
||||
if (attempt === retries) {
|
||||
console.error("AppleScript execution error after retries:", error);
|
||||
throw new Error(`AppleScript error: ${error.message}`);
|
||||
}
|
||||
// Retry with exponential backoff
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, RETRY_DELAY * Math.pow(2, attempt)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async findTabById(tabId) {
|
||||
const script = `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tabId}" then
|
||||
return {w, t, true}
|
||||
end if
|
||||
end repeat
|
||||
end repeat
|
||||
return {null, null, false}
|
||||
end tell
|
||||
`;
|
||||
return this.executeAppleScript(script);
|
||||
}
|
||||
|
||||
async executeTabOperation(
|
||||
tabId,
|
||||
operation,
|
||||
successMessage = "Operation completed",
|
||||
) {
|
||||
if (!tabId) {
|
||||
// No tab ID, execute on active tab
|
||||
return this.executeAppleScript(operation.activeScript);
|
||||
}
|
||||
|
||||
const script = `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tabId}" then
|
||||
${operation.tabScript}
|
||||
return "${successMessage}"
|
||||
end if
|
||||
end repeat
|
||||
end repeat
|
||||
return "Tab not found"
|
||||
end tell
|
||||
`;
|
||||
return this.executeAppleScript(script);
|
||||
}
|
||||
|
||||
setupHandlers() {
|
||||
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: [
|
||||
{
|
||||
name: "open_url",
|
||||
description: "Open a URL in Chrome",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
url: { type: "string", description: "URL to open" },
|
||||
new_tab: {
|
||||
type: "boolean",
|
||||
description: "Open in a new tab",
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
required: ["url"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get_current_tab",
|
||||
description: "Get information about the current active tab",
|
||||
inputSchema: { type: "object", properties: {} },
|
||||
},
|
||||
{
|
||||
name: "list_tabs",
|
||||
description: "List all open tabs in Chrome",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
window_id: {
|
||||
type: "number",
|
||||
description: "Specific window ID to list tabs from",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "close_tab",
|
||||
description: "Close a specific tab",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: { type: "number", description: "ID of the tab to close" },
|
||||
},
|
||||
required: ["tab_id"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "switch_to_tab",
|
||||
description: "Switch to a specific tab",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: {
|
||||
type: "number",
|
||||
description: "ID of the tab to switch to",
|
||||
},
|
||||
},
|
||||
required: ["tab_id"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reload_tab",
|
||||
description: "Reload a tab",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: {
|
||||
type: "number",
|
||||
description: "ID of the tab to reload",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "go_back",
|
||||
description: "Navigate back in browser history",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: { type: "number", description: "ID of the tab" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "go_forward",
|
||||
description: "Navigate forward in browser history",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: { type: "number", description: "ID of the tab" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "execute_javascript",
|
||||
description: "Execute JavaScript in the current tab",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
code: {
|
||||
type: "string",
|
||||
description: "JavaScript code to execute",
|
||||
},
|
||||
tab_id: { type: "number", description: "ID of the tab" },
|
||||
},
|
||||
required: ["code"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get_page_content",
|
||||
description: "Get the text content of the current page",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tab_id: { type: "number", description: "ID of the tab" },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
try {
|
||||
// Check Chrome availability first
|
||||
const isChromeAvailable = await this.checkChromeAvailable();
|
||||
if (!isChromeAvailable) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Error: Google Chrome is not available or not running",
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "open_url": {
|
||||
const { url, new_tab = true } = args;
|
||||
if (!url || typeof url !== "string") {
|
||||
throw new Error("URL is required and must be a string");
|
||||
}
|
||||
|
||||
const escapedUrl = this.escapeForAppleScript(url);
|
||||
const script = new_tab
|
||||
? `tell application "Google Chrome" to open location "${escapedUrl}"`
|
||||
: `tell application "Google Chrome" to set URL of active tab of front window to "${escapedUrl}"`;
|
||||
|
||||
await this.executeAppleScript(script);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
action: new_tab
|
||||
? "opened_new_tab"
|
||||
: "navigated_current_tab",
|
||||
url: url,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "get_current_tab": {
|
||||
const script = `
|
||||
tell application "Google Chrome"
|
||||
set currentTab to active tab of front window
|
||||
set tabInfo to {URL of currentTab, title of currentTab, id of currentTab}
|
||||
return tabInfo
|
||||
end tell
|
||||
`;
|
||||
const result = await this.executeAppleScript(script);
|
||||
const [url, title, id] = result.split(", ");
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
url,
|
||||
title,
|
||||
id: parseInt(id),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "list_tabs": {
|
||||
const script = `
|
||||
tell application "Google Chrome"
|
||||
set tabsList to {}
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
set end of tabsList to {id of t as string, URL of t, title of t}
|
||||
end repeat
|
||||
end repeat
|
||||
set AppleScript's text item delimiters to "|"
|
||||
set output to ""
|
||||
repeat with tabInfo in tabsList
|
||||
set output to output & (item 1 of tabInfo) & "," & (item 2 of tabInfo) & "," & (item 3 of tabInfo) & "|"
|
||||
end repeat
|
||||
return output
|
||||
end tell
|
||||
`;
|
||||
const result = await this.executeAppleScript(script);
|
||||
const tabs = result
|
||||
.split("|")
|
||||
.filter((tab) => tab)
|
||||
.map((tab) => {
|
||||
const [id, url, title] = tab.split(",");
|
||||
return { id: parseInt(id), url, title };
|
||||
});
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
tabs: tabs,
|
||||
count: tabs.length,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "close_tab": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const result = await this.executeTabOperation(
|
||||
tab_id,
|
||||
{
|
||||
tabScript: "close t",
|
||||
activeScript: `
|
||||
tell application "Google Chrome"
|
||||
close active tab of front window
|
||||
return "Tab closed"
|
||||
end tell
|
||||
`,
|
||||
},
|
||||
"Tab closed",
|
||||
);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result === "Tab closed",
|
||||
message: result,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "switch_to_tab": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const result = await this.executeTabOperation(
|
||||
tab_id,
|
||||
{
|
||||
tabScript: `
|
||||
set active tab of w to t
|
||||
set index of w to 1
|
||||
activate
|
||||
`,
|
||||
activeScript: `
|
||||
tell application "Google Chrome"
|
||||
activate
|
||||
return "Chrome activated"
|
||||
end tell
|
||||
`,
|
||||
},
|
||||
"Switched to tab",
|
||||
);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result !== "Tab not found",
|
||||
message: result,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "reload_tab": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const result = await this.executeTabOperation(
|
||||
tab_id,
|
||||
{
|
||||
tabScript: "reload t",
|
||||
activeScript: `
|
||||
tell application "Google Chrome"
|
||||
reload active tab of front window
|
||||
return "Tab reloaded"
|
||||
end tell
|
||||
`,
|
||||
},
|
||||
"Tab reloaded",
|
||||
);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result !== "Tab not found",
|
||||
message: result,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "go_back": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const result = await this.executeTabOperation(
|
||||
tab_id,
|
||||
{
|
||||
tabScript: "go back t",
|
||||
activeScript: `
|
||||
tell application "Google Chrome"
|
||||
go back active tab of front window
|
||||
return "Navigated back"
|
||||
end tell
|
||||
`,
|
||||
},
|
||||
"Navigated back",
|
||||
);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result !== "Tab not found",
|
||||
message: result,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "go_forward": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const result = await this.executeTabOperation(
|
||||
tab_id,
|
||||
{
|
||||
tabScript: "go forward t",
|
||||
activeScript: `
|
||||
tell application "Google Chrome"
|
||||
go forward active tab of front window
|
||||
return "Navigated forward"
|
||||
end tell
|
||||
`,
|
||||
},
|
||||
"Navigated forward",
|
||||
);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result !== "Tab not found",
|
||||
message: result,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "execute_javascript": {
|
||||
const { code, tab_id } = args;
|
||||
if (!code || typeof code !== "string") {
|
||||
throw new Error(
|
||||
"JavaScript code is required and must be a string",
|
||||
);
|
||||
}
|
||||
|
||||
// Wrap the code to capture console.log outputs
|
||||
const wrappedCode = `
|
||||
(function() {
|
||||
const logs = [];
|
||||
const originalLog = console.log;
|
||||
const originalWarn = console.warn;
|
||||
const originalError = console.error;
|
||||
const originalInfo = console.info;
|
||||
|
||||
console.log = function(...args) {
|
||||
logs.push({type: 'log', message: args.map(arg => {
|
||||
try {
|
||||
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
||||
} catch (e) {
|
||||
return String(arg);
|
||||
}
|
||||
}).join(' ')});
|
||||
originalLog.apply(console, args);
|
||||
};
|
||||
|
||||
console.warn = function(...args) {
|
||||
logs.push({type: 'warn', message: args.map(arg => {
|
||||
try {
|
||||
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
||||
} catch (e) {
|
||||
return String(arg);
|
||||
}
|
||||
}).join(' ')});
|
||||
originalWarn.apply(console, args);
|
||||
};
|
||||
|
||||
console.error = function(...args) {
|
||||
logs.push({type: 'error', message: args.map(arg => {
|
||||
try {
|
||||
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
||||
} catch (e) {
|
||||
return String(arg);
|
||||
}
|
||||
}).join(' ')});
|
||||
originalError.apply(console, args);
|
||||
};
|
||||
|
||||
console.info = function(...args) {
|
||||
logs.push({type: 'info', message: args.map(arg => {
|
||||
try {
|
||||
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
|
||||
} catch (e) {
|
||||
return String(arg);
|
||||
}
|
||||
}).join(' ')});
|
||||
originalInfo.apply(console, args);
|
||||
};
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = (function() {
|
||||
${code}
|
||||
})();
|
||||
} catch (error) {
|
||||
result = {error: error.toString(), stack: error.stack};
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
console.warn = originalWarn;
|
||||
console.error = originalError;
|
||||
console.info = originalInfo;
|
||||
}
|
||||
|
||||
return {
|
||||
result: result,
|
||||
logs: logs
|
||||
};
|
||||
})();
|
||||
`;
|
||||
|
||||
const escapedCode = this.escapeForAppleScript(wrappedCode);
|
||||
|
||||
const script = tab_id
|
||||
? `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tab_id}" then
|
||||
set result to execute t javascript "${escapedCode}"
|
||||
return result
|
||||
end if
|
||||
end repeat
|
||||
end repeat
|
||||
return "Tab not found"
|
||||
end tell
|
||||
`
|
||||
: `
|
||||
tell application "Google Chrome"
|
||||
execute active tab of front window javascript "${escapedCode}"
|
||||
end tell
|
||||
`;
|
||||
|
||||
const result = await this.executeAppleScript(script);
|
||||
|
||||
// Parse the result to extract logs and actual result
|
||||
try {
|
||||
const parsed = JSON.parse(result);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
logs: parsed.logs || [],
|
||||
result: parsed.result,
|
||||
hasErrors:
|
||||
parsed.result && parsed.result.error ? true : false,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
} catch (e) {
|
||||
// If parsing fails, return structured error
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: false,
|
||||
error: "Failed to parse JavaScript execution result",
|
||||
rawResult: result || "No result returned",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
case "get_page_content": {
|
||||
const { tab_id } = args;
|
||||
|
||||
const jsCode = "document.body.innerText";
|
||||
const script = tab_id
|
||||
? `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tab_id}" then
|
||||
set pageContent to execute t javascript "${jsCode}"
|
||||
return pageContent
|
||||
end if
|
||||
end repeat
|
||||
end repeat
|
||||
return "Tab not found"
|
||||
end tell
|
||||
`
|
||||
: `
|
||||
tell application "Google Chrome"
|
||||
execute active tab of front window javascript "${jsCode}"
|
||||
end tell
|
||||
`;
|
||||
|
||||
const result = await this.executeAppleScript(script);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: result !== "Tab not found",
|
||||
content: result,
|
||||
contentLength: result.length,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error in tool '${name}':`, error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
tool: name,
|
||||
args: args,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run() {
|
||||
try {
|
||||
const isChromeAvailable = await this.checkChromeAvailable();
|
||||
if (!isChromeAvailable) {
|
||||
console.error("Warning: Google Chrome is not available or not running");
|
||||
}
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await this.server.connect(transport);
|
||||
console.error("Chrome AppleScript MCP server running on stdio");
|
||||
} catch (error) {
|
||||
console.error("Failed to start Chrome AppleScript MCP server:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const server = new ChromeControlServer();
|
||||
server.run().catch(console.error);
|
||||
90
examples/chrome-applescript/yarn.lock
Normal file
90
examples/chrome-applescript/yarn.lock
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@modelcontextprotocol/sdk@^0.6.0":
|
||||
version "0.6.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/@modelcontextprotocol/sdk/-/sdk-0.6.1.tgz#4e144155992749faf191faa512ac0c7a23152522"
|
||||
integrity sha512-OkVXMix3EIbB5Z6yife2XTrSlOnVvCLR1Kg91I4pYFEsV9RbnoyQVScXCuVhGaZHOnTZgso8lMQN1Po2TadGKQ==
|
||||
dependencies:
|
||||
content-type "^1.0.5"
|
||||
raw-body "^3.0.0"
|
||||
zod "^3.23.8"
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
content-type@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
||||
depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
http-errors@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
iconv-lite@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
inherits@2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
raw-body@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f"
|
||||
integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.6.3"
|
||||
unpipe "1.0.0"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3.0.0":
|
||||
version "2.1.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/safer-buffer/2.1.2/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
toidentifier@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
unpipe@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
||||
|
||||
zod@^3.23.8:
|
||||
version "3.25.55"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/zod/-/zod-3.25.55.tgz#b1ffd48a34f558d1a912d1ed6bf84a6ca692fbe1"
|
||||
integrity sha512-219huNnkSLQnLsQ3uaRjXsxMrVm5C9W3OOpEVt2k5tvMKuA8nBSu38e0B//a+he9Iq2dvmk2VyYVlHqiHa4YBA==
|
||||
77
examples/file-manager-python/manifest.json
Normal file
77
examples/file-manager-python/manifest.json
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"dxt_version": "0.1",
|
||||
"name": "file-manager-python",
|
||||
"display_name": "Python File Manager MCP",
|
||||
"version": "0.1.0",
|
||||
"description": "A Python MCP server for file operations",
|
||||
"long_description": "This extension provides file management capabilities through a Python MCP server. It demonstrates Python-based Desktop Extension development, including file operations, directory management, and proper MCP protocol implementation.",
|
||||
"author": {
|
||||
"name": "Anthropic",
|
||||
"email": "support@anthropic.com",
|
||||
"url": "https://github.com/anthropics"
|
||||
},
|
||||
"server": {
|
||||
"type": "python",
|
||||
"entry_point": "server/main.py",
|
||||
"mcp_config": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"${__dirname}/server/main.py",
|
||||
"--workspace=${user_config.workspace_directory}"
|
||||
],
|
||||
"env": {
|
||||
"DEBUG": "${user_config.debug_mode}",
|
||||
"PYTHONPATH": "${__dirname}/server/lib"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"name": "list_files",
|
||||
"description": "List files in a directory"
|
||||
},
|
||||
{
|
||||
"name": "read_file",
|
||||
"description": "Read file contents"
|
||||
},
|
||||
{
|
||||
"name": "get_file_info",
|
||||
"description": "Get information about a file"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"file",
|
||||
"directory",
|
||||
"python",
|
||||
"management",
|
||||
"filesystem"
|
||||
],
|
||||
"license": "MIT",
|
||||
"user_config": {
|
||||
"workspace_directory": {
|
||||
"type": "directory",
|
||||
"title": "Workspace Directory",
|
||||
"description": "Directory to use as workspace",
|
||||
"default": "${HOME}/Documents",
|
||||
"required": false
|
||||
},
|
||||
"debug_mode": {
|
||||
"type": "boolean",
|
||||
"title": "Debug Mode",
|
||||
"description": "Enable debug output",
|
||||
"default": false,
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=0.10.0",
|
||||
"platforms": [
|
||||
"darwin",
|
||||
"win32",
|
||||
"linux"
|
||||
],
|
||||
"runtimes": {
|
||||
"python": ">=3.8.0 <4"
|
||||
}
|
||||
}
|
||||
}
|
||||
31
examples/file-manager-python/pyproject.toml
Normal file
31
examples/file-manager-python/pyproject.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "file-manager-python"
|
||||
version = "0.1.0"
|
||||
description = "A Python MCP server for file operations"
|
||||
authors = [
|
||||
{name = "Anthropic", email = "support@anthropic.com"}
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
classifiers = [
|
||||
"Private :: Do Not Upload" # Prevents accidental uploads to PyPI
|
||||
]
|
||||
|
||||
[project.dependencies]
|
||||
mcp = ">=1.0.0"
|
||||
trio = ">=0.22.0"
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["server"]
|
||||
|
||||
[project.scripts]
|
||||
bundle-deps = "python:install_deps"
|
||||
|
||||
# Custom scripts section for DXT development
|
||||
[tool.dxt]
|
||||
bundle = "pip install \"mcp[all]\" --target server/lib --upgrade --force-reinstall"
|
||||
test = "python server/main.py --debug"
|
||||
pack = "npx @anthropic-ai/dxt pack"
|
||||
2
examples/file-manager-python/requirements.txt
Normal file
2
examples/file-manager-python/requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mcp>=1.0.0
|
||||
trio>=0.22.0
|
||||
112
examples/file-manager-python/server/main.py
Normal file
112
examples/file-manager-python/server/main.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
# Parse command line arguments
|
||||
parser = argparse.ArgumentParser(description="File Manager MCP Server")
|
||||
parser.add_argument(
|
||||
"--workspace", default=os.path.expanduser("~/Documents"), help="Workspace directory"
|
||||
)
|
||||
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Initialize server
|
||||
mcp = FastMCP("file-manager-python")
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def list_files(path: str) -> str:
|
||||
"""List files in a directory"""
|
||||
path_obj = Path(path)
|
||||
|
||||
if not path_obj.exists():
|
||||
return f"Directory not found: {path}"
|
||||
|
||||
if not path_obj.is_dir():
|
||||
return f"Path is not a directory: {path}"
|
||||
|
||||
try:
|
||||
files = []
|
||||
for item in path_obj.iterdir():
|
||||
file_type = "directory" if item.is_dir() else "file"
|
||||
files.append(f"{item.name} ({file_type})")
|
||||
|
||||
if not files:
|
||||
return f"Directory is empty: {path}"
|
||||
|
||||
file_list = "\n".join(files)
|
||||
return f"Files in {path}:\n{file_list}"
|
||||
|
||||
except PermissionError:
|
||||
return f"Permission denied accessing: {path}"
|
||||
except Exception as e:
|
||||
return f"Error listing directory: {str(e)}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def read_file(path: str) -> str:
|
||||
"""Read file contents"""
|
||||
path_obj = Path(path)
|
||||
|
||||
if not path_obj.exists():
|
||||
return f"File not found: {path}"
|
||||
|
||||
if not path_obj.is_file():
|
||||
return f"Path is not a file: {path}"
|
||||
|
||||
try:
|
||||
with path_obj.open("r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
return f"Contents of {path}:\n{content}"
|
||||
|
||||
except UnicodeDecodeError:
|
||||
return f"File is not text or uses unsupported encoding: {path}"
|
||||
except PermissionError:
|
||||
return f"Permission denied reading: {path}"
|
||||
except Exception as e:
|
||||
return f"Error reading file: {str(e)}"
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def get_file_info(path: str) -> str:
|
||||
"""Get information about a file"""
|
||||
path_obj = Path(path)
|
||||
|
||||
if not path_obj.exists():
|
||||
return f"Path not found: {path}"
|
||||
|
||||
try:
|
||||
stat_info = path_obj.stat()
|
||||
file_type = "directory" if path_obj.is_dir() else "file"
|
||||
|
||||
info = [
|
||||
f"Path: {path}",
|
||||
f"Type: {file_type}",
|
||||
f"Size: {stat_info.st_size} bytes",
|
||||
f"Modified: {stat_info.st_mtime}",
|
||||
f"Created: {stat_info.st_ctime}",
|
||||
]
|
||||
|
||||
info_text = "\n".join(info)
|
||||
return f"File Info:\n{info_text}"
|
||||
|
||||
except PermissionError:
|
||||
return f"Permission denied accessing: {path}"
|
||||
except Exception as e:
|
||||
return f"Error getting file info: {str(e)}"
|
||||
|
||||
|
||||
# Main execution
|
||||
if __name__ == "__main__":
|
||||
# Debug output if enabled
|
||||
if args.debug:
|
||||
print("Starting File Manager MCP Server...", file=sys.stderr)
|
||||
print(f"Workspace: {args.workspace}", file=sys.stderr)
|
||||
|
||||
# Run the server
|
||||
mcp.run()
|
||||
BIN
examples/hello-world-node/icon.png
Normal file
BIN
examples/hello-world-node/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 494 KiB |
106
examples/hello-world-node/manifest.json
Normal file
106
examples/hello-world-node/manifest.json
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
"dxt_version": "0.1",
|
||||
"name": "hello-world-node",
|
||||
"display_name": "Hello World MCP Server (Reference Extension)",
|
||||
"version": "0.1.0",
|
||||
"description": "A reference MCP extension demonstrating best practices and all available features",
|
||||
"long_description": "This is a reference implementation of a Desktop Extension (DXT). It demonstrates all available manifest features, user configuration options, and security best practices. Use this extension as a template when creating your own MCP servers. The extension includes examples of all user configuration types, proper request token verification, and comprehensive metadata fields.",
|
||||
"author": {
|
||||
"name": "Acme Inc",
|
||||
"email": "support@acme.void",
|
||||
"url": "https://www.acme.void"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/acme/my-repo"
|
||||
},
|
||||
"homepage": "https://docs.acme.void/my-repo/extensions",
|
||||
"documentation": "https://docs.acme.void/my-repo/extensions/hello-world",
|
||||
"support": "https://github.com/acme/my-repo/issues",
|
||||
"icon": "icon.png",
|
||||
"server": {
|
||||
"type": "node",
|
||||
"entry_point": "server/index.js",
|
||||
"mcp_config": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"${__dirname}/server/index.js",
|
||||
"--verbose=${user_config.verbose_logging}",
|
||||
"--max-results=${user_config.max_results}",
|
||||
"--config=${user_config.config_file}",
|
||||
"--workspace=${user_config.workspace_directory}"
|
||||
],
|
||||
"env": {
|
||||
"API_KEY": "${user_config.api_key}",
|
||||
"DEBUG": "${user_config.debug_mode}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_current_time",
|
||||
"description": "Get the current computer time in various formats"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"reference",
|
||||
"example",
|
||||
"hello-world",
|
||||
"tutorial",
|
||||
"mcp",
|
||||
"time"
|
||||
],
|
||||
"license": "MIT",
|
||||
"user_config": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"title": "API Key",
|
||||
"description": "Your API key for authentication (example of sensitive string)",
|
||||
"sensitive": true,
|
||||
"required": false
|
||||
},
|
||||
"verbose_logging": {
|
||||
"type": "boolean",
|
||||
"title": "Verbose Logging",
|
||||
"description": "Enable detailed logging output",
|
||||
"default": false,
|
||||
"required": false
|
||||
},
|
||||
"max_results": {
|
||||
"type": "number",
|
||||
"title": "Maximum Results",
|
||||
"description": "Maximum number of results to return",
|
||||
"default": 10,
|
||||
"min": 1,
|
||||
"max": 100,
|
||||
"required": false
|
||||
},
|
||||
"config_file": {
|
||||
"type": "file",
|
||||
"title": "Configuration File",
|
||||
"description": "Path to a JSON configuration file",
|
||||
"required": false
|
||||
},
|
||||
"workspace_directory": {
|
||||
"type": "directory",
|
||||
"title": "Workspace Directory",
|
||||
"description": "Directory to use as workspace",
|
||||
"default": "${HOME}/Documents",
|
||||
"required": false
|
||||
},
|
||||
"debug_mode": {
|
||||
"type": "string",
|
||||
"title": "Debug Mode",
|
||||
"description": "Set debug level (example of non-sensitive string)",
|
||||
"default": "info",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"compatibility": {
|
||||
"claude_desktop": ">=0.10.0",
|
||||
"platforms": ["darwin", "win32", "linux"],
|
||||
"runtimes": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
examples/hello-world-node/package.json
Normal file
11
examples/hello-world-node/package.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "hello-world-node",
|
||||
"version": "0.1.0",
|
||||
"description": "A simple MCP server that returns the current time",
|
||||
"type": "module",
|
||||
"main": "server/index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.12.1"
|
||||
}
|
||||
}
|
||||
70
examples/hello-world-node/server/index.js
Normal file
70
examples/hello-world-node/server/index.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: "hello-world-node",
|
||||
version: "1.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Handle tool listing
|
||||
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: "get_current_time",
|
||||
description: "Get the current computer time",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// Handle tool execution
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
if (request.params.name === "get_current_time") {
|
||||
const now = new Date();
|
||||
const timeString = now.toLocaleString("en-US", {
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
timeZoneName: "short",
|
||||
});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `The current time is: ${timeString}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
});
|
||||
|
||||
// Start the server
|
||||
const transport = new StdioServerTransport();
|
||||
server.connect(transport);
|
||||
|
||||
console.error("Hello World MCP server running...");
|
||||
621
examples/hello-world-node/yarn.lock
Normal file
621
examples/hello-world-node/yarn.lock
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@modelcontextprotocol/sdk@^1.12.1":
|
||||
version "1.12.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz#f77503f0263b33cb1e5b81a6ff0c322393cabd37"
|
||||
integrity sha512-KG1CZhZfWg+u8pxeM/mByJDScJSrjjxLc8fwQqbsS8xCjBmQfMNEBTotYdNanKekepnfRI85GtgQlctLFpcYPw==
|
||||
dependencies:
|
||||
ajv "^6.12.6"
|
||||
content-type "^1.0.5"
|
||||
cors "^2.8.5"
|
||||
cross-spawn "^7.0.5"
|
||||
eventsource "^3.0.2"
|
||||
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"
|
||||
|
||||
accepts@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895"
|
||||
integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==
|
||||
dependencies:
|
||||
mime-types "^3.0.0"
|
||||
negotiator "^1.0.0"
|
||||
|
||||
ajv@^6.12.6:
|
||||
version "6.12.6"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
body-parser@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa"
|
||||
integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==
|
||||
dependencies:
|
||||
bytes "^3.1.2"
|
||||
content-type "^1.0.5"
|
||||
debug "^4.4.0"
|
||||
http-errors "^2.0.0"
|
||||
iconv-lite "^0.6.3"
|
||||
on-finished "^2.4.1"
|
||||
qs "^6.14.0"
|
||||
raw-body "^3.0.0"
|
||||
type-is "^2.0.0"
|
||||
|
||||
bytes@3.1.2, bytes@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
|
||||
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
|
||||
call-bound@^1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
|
||||
integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.2"
|
||||
get-intrinsic "^1.3.0"
|
||||
|
||||
content-disposition@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2"
|
||||
integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==
|
||||
dependencies:
|
||||
safe-buffer "5.2.1"
|
||||
|
||||
content-type@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
||||
cookie-signature@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
|
||||
integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
|
||||
|
||||
cookie@^0.7.1:
|
||||
version "0.7.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
|
||||
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cross-spawn@^7.0.5:
|
||||
version "7.0.6"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
debug@^4.3.5, debug@^4.4.0:
|
||||
version "4.4.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
depd@2.0.0, depd@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
dunder-proto@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
||||
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.1"
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.2.0"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
|
||||
|
||||
encodeurl@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
|
||||
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
||||
|
||||
es-define-property@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
|
||||
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
||||
|
||||
es-errors@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||
|
||||
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
|
||||
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
|
||||
escape-html@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||
|
||||
etag@^1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||
|
||||
eventsource-parser@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/eventsource-parser/-/eventsource-parser-3.0.2.tgz#0fea1abd26eca8201099ff5212f6c4e7ca2fd5d3"
|
||||
integrity sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==
|
||||
|
||||
eventsource@^3.0.2:
|
||||
version "3.0.7"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/eventsource/-/eventsource-3.0.7.tgz#1157622e2f5377bb6aef2114372728ba0c156989"
|
||||
integrity sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==
|
||||
dependencies:
|
||||
eventsource-parser "^3.0.1"
|
||||
|
||||
express-rate-limit@^7.5.0:
|
||||
version "7.5.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f"
|
||||
integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==
|
||||
|
||||
express@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9"
|
||||
integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==
|
||||
dependencies:
|
||||
accepts "^2.0.0"
|
||||
body-parser "^2.2.0"
|
||||
content-disposition "^1.0.0"
|
||||
content-type "^1.0.5"
|
||||
cookie "^0.7.1"
|
||||
cookie-signature "^1.2.1"
|
||||
debug "^4.4.0"
|
||||
encodeurl "^2.0.0"
|
||||
escape-html "^1.0.3"
|
||||
etag "^1.8.1"
|
||||
finalhandler "^2.1.0"
|
||||
fresh "^2.0.0"
|
||||
http-errors "^2.0.0"
|
||||
merge-descriptors "^2.0.0"
|
||||
mime-types "^3.0.0"
|
||||
on-finished "^2.4.1"
|
||||
once "^1.4.0"
|
||||
parseurl "^1.3.3"
|
||||
proxy-addr "^2.0.7"
|
||||
qs "^6.14.0"
|
||||
range-parser "^1.2.1"
|
||||
router "^2.2.0"
|
||||
send "^1.1.0"
|
||||
serve-static "^2.2.0"
|
||||
statuses "^2.0.1"
|
||||
type-is "^2.0.1"
|
||||
vary "^1.1.2"
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.3"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
finalhandler@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f"
|
||||
integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==
|
||||
dependencies:
|
||||
debug "^4.4.0"
|
||||
encodeurl "^2.0.0"
|
||||
escape-html "^1.0.3"
|
||||
on-finished "^2.4.1"
|
||||
parseurl "^1.3.3"
|
||||
statuses "^2.0.1"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
|
||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||
|
||||
fresh@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4"
|
||||
integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
get-intrinsic@^1.2.5, get-intrinsic@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
|
||||
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
|
||||
dependencies:
|
||||
call-bind-apply-helpers "^1.0.2"
|
||||
es-define-property "^1.0.1"
|
||||
es-errors "^1.3.0"
|
||||
es-object-atoms "^1.1.1"
|
||||
function-bind "^1.1.2"
|
||||
get-proto "^1.0.1"
|
||||
gopd "^1.2.0"
|
||||
has-symbols "^1.1.0"
|
||||
hasown "^2.0.2"
|
||||
math-intrinsics "^1.1.0"
|
||||
|
||||
get-proto@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
|
||||
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
|
||||
dependencies:
|
||||
dunder-proto "^1.0.1"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
gopd@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
|
||||
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
||||
|
||||
has-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
|
||||
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
|
||||
|
||||
hasown@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
http-errors@2.0.0, http-errors@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
iconv-lite@0.6.3, iconv-lite@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
inherits@2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
|
||||
|
||||
is-promise@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
|
||||
integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/json-schema-traverse/0.4.1/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha1-afaofZUTq4u4/mO9sJecRI5oRmA=
|
||||
|
||||
math-intrinsics@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
||||
|
||||
media-typer@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561"
|
||||
integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==
|
||||
|
||||
merge-descriptors@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808"
|
||||
integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
|
||||
|
||||
mime-db@^1.54.0:
|
||||
version "1.54.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
|
||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||
|
||||
mime-types@^3.0.0, mime-types@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
|
||||
integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
|
||||
dependencies:
|
||||
mime-db "^1.54.0"
|
||||
|
||||
ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
negotiator@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
|
||||
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
|
||||
|
||||
object-assign@^4:
|
||||
version "4.1.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
object-inspect@^1.13.3:
|
||||
version "1.13.4"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
|
||||
integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
|
||||
|
||||
on-finished@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
|
||||
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
parseurl@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
|
||||
|
||||
path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-to-regexp@^8.0.0:
|
||||
version "8.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4"
|
||||
integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==
|
||||
|
||||
pkce-challenge@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97"
|
||||
integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==
|
||||
|
||||
proxy-addr@^2.0.7:
|
||||
version "2.0.7"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
|
||||
dependencies:
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
|
||||
qs@^6.14.0:
|
||||
version "6.14.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
|
||||
integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
|
||||
dependencies:
|
||||
side-channel "^1.1.0"
|
||||
|
||||
range-parser@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||
|
||||
raw-body@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f"
|
||||
integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.6.3"
|
||||
unpipe "1.0.0"
|
||||
|
||||
router@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef"
|
||||
integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==
|
||||
dependencies:
|
||||
debug "^4.4.0"
|
||||
depd "^2.0.0"
|
||||
is-promise "^4.0.0"
|
||||
parseurl "^1.3.3"
|
||||
path-to-regexp "^8.0.0"
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3.0.0":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
send@^1.1.0, send@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212"
|
||||
integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==
|
||||
dependencies:
|
||||
debug "^4.3.5"
|
||||
encodeurl "^2.0.0"
|
||||
escape-html "^1.0.3"
|
||||
etag "^1.8.1"
|
||||
fresh "^2.0.0"
|
||||
http-errors "^2.0.0"
|
||||
mime-types "^3.0.1"
|
||||
ms "^2.1.3"
|
||||
on-finished "^2.4.1"
|
||||
range-parser "^1.2.1"
|
||||
statuses "^2.0.1"
|
||||
|
||||
serve-static@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9"
|
||||
integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==
|
||||
dependencies:
|
||||
encodeurl "^2.0.0"
|
||||
escape-html "^1.0.3"
|
||||
parseurl "^1.3.3"
|
||||
send "^1.2.0"
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
|
||||
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
||||
dependencies:
|
||||
shebang-regex "^3.0.0"
|
||||
|
||||
shebang-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
side-channel-list@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
|
||||
integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
object-inspect "^1.13.3"
|
||||
|
||||
side-channel-map@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
|
||||
integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
|
||||
dependencies:
|
||||
call-bound "^1.0.2"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.5"
|
||||
object-inspect "^1.13.3"
|
||||
|
||||
side-channel-weakmap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
|
||||
integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
|
||||
dependencies:
|
||||
call-bound "^1.0.2"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.5"
|
||||
object-inspect "^1.13.3"
|
||||
side-channel-map "^1.0.1"
|
||||
|
||||
side-channel@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
|
||||
integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
object-inspect "^1.13.3"
|
||||
side-channel-list "^1.0.0"
|
||||
side-channel-map "^1.0.1"
|
||||
side-channel-weakmap "^1.0.2"
|
||||
|
||||
statuses@2.0.1, statuses@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
toidentifier@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
type-is@^2.0.0, type-is@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97"
|
||||
integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==
|
||||
dependencies:
|
||||
content-type "^1.0.5"
|
||||
media-typer "^1.1.0"
|
||||
mime-types "^3.0.0"
|
||||
|
||||
unpipe@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
vary@^1, vary@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/wrappy/1.0.2/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
zod-to-json-schema@^3.24.1:
|
||||
version "3.24.5"
|
||||
resolved "https://artifactory.infra.ant.dev:443/artifactory/api/npm/npm-all/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3"
|
||||
integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==
|
||||
|
||||
zod@^3.23.8:
|
||||
version "3.25.63"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.63.tgz#5eac66b56aa9f5e1cd3604dd541b819110474efa"
|
||||
integrity sha512-3ttCkqhtpncYXfP0f6dsyabbYV/nEUW+Xlu89jiXbTBifUfjaSqXOG6JnQPLtqt87n7KAmnMqcjay6c0Wq0Vbw==
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue