onlymcp 0.16.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +33 -17
- package/README.md +7 -1
- package/dist/bin/cli.js +46 -564
- package/dist/bin/mcp.js +45 -66
- package/package.json +6 -10
- package/dist/apiBaseUrl.d.ts +0 -12
- package/dist/apiBaseUrl.js +0 -28
- package/dist/apiBaseUrl.js.map +0 -1
- package/dist/apiClient.d.ts +0 -296
- package/dist/apiClient.js +0 -224
- package/dist/apiClient.js.map +0 -1
- package/dist/auth/deviceLogin.d.ts +0 -5
- package/dist/auth/deviceLogin.js +0 -40
- package/dist/auth/deviceLogin.js.map +0 -1
- package/dist/auth/keyring.d.ts +0 -5
- package/dist/auth/keyring.js +0 -28
- package/dist/auth/keyring.js.map +0 -1
- package/dist/bin/cli.d.ts +0 -2
- package/dist/bin/cli.js.map +0 -1
- package/dist/bin/mcp.d.ts +0 -2
- package/dist/bin/mcp.js.map +0 -1
- package/dist/cache.d.ts +0 -7
- package/dist/cache.js +0 -32
- package/dist/cache.js.map +0 -1
- package/dist/deviceId.d.ts +0 -2
- package/dist/deviceId.js +0 -97
- package/dist/deviceId.js.map +0 -1
- package/dist/export/unpack.d.ts +0 -33
- package/dist/export/unpack.js +0 -54
- package/dist/export/unpack.js.map +0 -1
- package/dist/identity.d.ts +0 -29
- package/dist/identity.js +0 -116
- package/dist/identity.js.map +0 -1
- package/dist/import/collect.d.ts +0 -25
- package/dist/import/collect.js +0 -101
- package/dist/import/collect.js.map +0 -1
- package/dist/import/frontmatter.d.ts +0 -44
- package/dist/import/frontmatter.js +0 -93
- package/dist/import/frontmatter.js.map +0 -1
- package/dist/import/plan.d.ts +0 -74
- package/dist/import/plan.js +0 -190
- package/dist/import/plan.js.map +0 -1
- package/dist/import/prune.d.ts +0 -46
- package/dist/import/prune.js +0 -61
- package/dist/import/prune.js.map +0 -1
- package/dist/import/secrets.d.ts +0 -7
- package/dist/import/secrets.js +0 -77
- package/dist/import/secrets.js.map +0 -1
- package/dist/import/upload.d.ts +0 -21
- package/dist/import/upload.js +0 -99
- package/dist/import/upload.js.map +0 -1
- package/dist/install.d.ts +0 -81
- package/dist/install.js +0 -168
- package/dist/install.js.map +0 -1
- package/dist/instructions.d.ts +0 -4
- package/dist/instructions.js +0 -67
- package/dist/instructions.js.map +0 -1
- package/dist/memoryPath.d.ts +0 -1
- package/dist/memoryPath.js +0 -13
- package/dist/memoryPath.js.map +0 -1
- package/dist/memorySync.d.ts +0 -28
- package/dist/memorySync.js +0 -56
- package/dist/memorySync.js.map +0 -1
- package/dist/paths.d.ts +0 -16
- package/dist/paths.js +0 -58
- package/dist/paths.js.map +0 -1
- package/dist/registry/caveats.d.ts +0 -17
- package/dist/registry/caveats.js +0 -74
- package/dist/registry/caveats.js.map +0 -1
- package/dist/registry/clients.d.ts +0 -17
- package/dist/registry/clients.js +0 -402
- package/dist/registry/clients.js.map +0 -1
- package/dist/registry/index.d.ts +0 -6
- package/dist/registry/index.js +0 -7
- package/dist/registry/index.js.map +0 -1
- package/dist/registry/serverInfo.d.ts +0 -25
- package/dist/registry/serverInfo.js +0 -33
- package/dist/registry/serverInfo.js.map +0 -1
- package/dist/registry/servers.d.ts +0 -58
- package/dist/registry/servers.js +0 -259
- package/dist/registry/servers.js.map +0 -1
- package/dist/registry/toolHints.d.ts +0 -29
- package/dist/registry/toolHints.js +0 -41
- package/dist/registry/toolHints.js.map +0 -1
- package/dist/registry/types.d.ts +0 -71
- package/dist/registry/types.js +0 -6
- package/dist/registry/types.js.map +0 -1
- package/dist/skillFilePath.d.ts +0 -1
- package/dist/skillFilePath.js +0 -29
- package/dist/skillFilePath.js.map +0 -1
- package/dist/stubs.d.ts +0 -7
- package/dist/stubs.js +0 -159
- package/dist/stubs.js.map +0 -1
- package/dist/tools/connections.d.ts +0 -154
- package/dist/tools/connections.js +0 -164
- package/dist/tools/connections.js.map +0 -1
- package/dist/tools/getAgentDefinition.d.ts +0 -26
- package/dist/tools/getAgentDefinition.js +0 -29
- package/dist/tools/getAgentDefinition.js.map +0 -1
- package/dist/tools/getSkill.d.ts +0 -26
- package/dist/tools/getSkill.js +0 -26
- package/dist/tools/getSkill.js.map +0 -1
- package/dist/tools/getSkillFile.d.ts +0 -27
- package/dist/tools/getSkillFile.js +0 -39
- package/dist/tools/getSkillFile.js.map +0 -1
- package/dist/tools/index.d.ts +0 -263
- package/dist/tools/index.js +0 -69
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/lists.d.ts +0 -38
- package/dist/tools/lists.js +0 -39
- package/dist/tools/lists.js.map +0 -1
- package/dist/tools/memoryGraph.d.ts +0 -69
- package/dist/tools/memoryGraph.js +0 -128
- package/dist/tools/memoryGraph.js.map +0 -1
- package/dist/tools/memoryRead.d.ts +0 -25
- package/dist/tools/memoryRead.js +0 -33
- package/dist/tools/memoryRead.js.map +0 -1
- package/dist/tools/memoryWrite.d.ts +0 -27
- package/dist/tools/memoryWrite.js +0 -34
- package/dist/tools/memoryWrite.js.map +0 -1
- package/dist/tools/write.d.ts +0 -166
- package/dist/tools/write.js +0 -193
- package/dist/tools/write.js.map +0 -1
package/dist/registry/servers.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The picture the product is named after: many MCP servers behind one
|
|
3
|
-
* connection. This list backs the rotating tiles in
|
|
4
|
-
* `packages/web/src/components/McpHub.tsx` and the docs page of connectable
|
|
5
|
-
* servers. Since 2026-10-18 it also seeds the server catalogue table
|
|
6
|
-
* (`packages/api/src/catalogue/store.ts`), which an admin edits and which
|
|
7
|
-
* `/api/mcp-catalog` and the "add a server" step of Connect read; only the
|
|
8
|
-
* addresses of this list are trusted for tool hints (api mcp/tool-hints.ts).
|
|
9
|
-
*
|
|
10
|
-
* Every server in the pool was verified, not remembered. Originally
|
|
11
|
-
* (2026-09-05): each URL was pushed through this product's own
|
|
12
|
-
* POST /api/mcp-connections/test, and only the ones that completed an MCP
|
|
13
|
-
* handshake or answered UNAUTHORIZED (which means a real MCP server is
|
|
14
|
-
* there and wants credentials) were listed. Dropped on that evidence:
|
|
15
|
-
* GitLab (mcp.gitlab.com does not resolve), Figma, Google Drive, Slack.
|
|
16
|
-
* Dropped for want of a brand icon: Canva, monday.com.
|
|
17
|
-
* GitLab came back on 2026-10-18 at gitlab.com/api/v4/mcp: an unauthenticated
|
|
18
|
-
* MCP initialize POST answered 401 with a `WWW-Authenticate: Bearer ...
|
|
19
|
-
* resource_metadata=...` header, and the OAuth metadata names a registration
|
|
20
|
-
* endpoint. Gamma joined the same day on the same evidence, with `brand: null`
|
|
21
|
-
* (simple-icons has no Gamma mark; the catalogue draws a letter tile).
|
|
22
|
-
*
|
|
23
|
-
* Re-verified 2026-09-25 for this registry, this time against each
|
|
24
|
-
* vendor's own documentation (`docsUrl` below) AND a fresh local probe: a
|
|
25
|
-
* scratch script POSTed an MCP `initialize` request, unauthenticated, to
|
|
26
|
-
* every URL below. All 17 answered `401` with a `WWW-Authenticate: Bearer`
|
|
27
|
-
* header naming an OAuth protected-resource metadata document (for
|
|
28
|
-
* example `resource_metadata="https://mcp.notion.com/.well-known/oauth-
|
|
29
|
-
* protected-resource/mcp"`), which is exactly what a live MCP server
|
|
30
|
-
* behind OAuth returns - confirming each URL is real and reachable, not
|
|
31
|
-
* only documented. The finer distinction of `auth` below (whether a
|
|
32
|
-
* static bearer token is ALSO accepted, alongside OAuth) came from each
|
|
33
|
-
* vendor's docs, because a 401 alone cannot tell OAuth-only apart from
|
|
34
|
-
* OAuth-or-bearer.
|
|
35
|
-
*
|
|
36
|
-
* One correction from the 2026-09-05 note: this pass found Linear's docs
|
|
37
|
-
* now document `Authorization: Bearer <token>` as an accepted alternative
|
|
38
|
-
* to the interactive OAuth flow. The original spec text (problem #6)
|
|
39
|
-
* called Linear OAuth-only as of that date; either that capability is new,
|
|
40
|
-
* or it was missed in the first pass. `auth` below reflects the current,
|
|
41
|
-
* re-verified state, and this comment records the discrepancy rather than
|
|
42
|
-
* silently overwriting it.
|
|
43
|
-
*
|
|
44
|
-
* The open MCP registry is not a usable source for this list, by the way -
|
|
45
|
-
* anyone may publish there, and a search for "github" returns community
|
|
46
|
-
* wrappers hosted by third parties, not GitHub's own server.
|
|
47
|
-
*
|
|
48
|
-
* `filesystem` and `postgres`, the textbook examples, are absent on purpose:
|
|
49
|
-
* they are local stdio processes, and OnlyMCP deliberately does not run those
|
|
50
|
-
* (a process we spawn on a user's behalf is code execution on our side, see
|
|
51
|
-
* docs/SECURITY.md).
|
|
52
|
-
*
|
|
53
|
-
* The prefixes are real. `github__create_issue` is exactly what a client
|
|
54
|
-
* sees, because the gateway namespaces every proxied tool with the
|
|
55
|
-
* connection's slug (packages/api/src/mcp/gateway.ts).
|
|
56
|
-
*/
|
|
57
|
-
export const SERVERS = [
|
|
58
|
-
{
|
|
59
|
-
id: 'github',
|
|
60
|
-
name: 'GitHub',
|
|
61
|
-
brand: 'github',
|
|
62
|
-
url: 'https://api.githubcopilot.com/mcp/',
|
|
63
|
-
auth: 'oauth-or-bearer',
|
|
64
|
-
docsUrl: 'https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp-in-your-ide/set-up-the-github-mcp-server',
|
|
65
|
-
verifiedOn: '2026-09-25',
|
|
66
|
-
suggestedSlug: 'github',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
id: 'linear',
|
|
70
|
-
name: 'Linear',
|
|
71
|
-
brand: 'linear',
|
|
72
|
-
url: 'https://mcp.linear.app/mcp',
|
|
73
|
-
auth: 'oauth-or-bearer',
|
|
74
|
-
docsUrl: 'https://linear.app/docs/mcp',
|
|
75
|
-
verifiedOn: '2026-09-25',
|
|
76
|
-
suggestedSlug: 'linear',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: 'notion',
|
|
80
|
-
name: 'Notion',
|
|
81
|
-
brand: 'notion',
|
|
82
|
-
url: 'https://mcp.notion.com/mcp',
|
|
83
|
-
auth: 'oauth',
|
|
84
|
-
docsUrl: 'https://developers.notion.com/guides/mcp/get-started-with-mcp',
|
|
85
|
-
verifiedOn: '2026-09-25',
|
|
86
|
-
suggestedSlug: 'notion',
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
id: 'sentry',
|
|
90
|
-
name: 'Sentry',
|
|
91
|
-
brand: 'sentry',
|
|
92
|
-
url: 'https://mcp.sentry.dev/mcp',
|
|
93
|
-
auth: 'oauth',
|
|
94
|
-
docsUrl: 'https://docs.sentry.io/product/mcp-servers/getting-started/',
|
|
95
|
-
verifiedOn: '2026-09-25',
|
|
96
|
-
suggestedSlug: 'sentry',
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: 'stripe',
|
|
100
|
-
name: 'Stripe',
|
|
101
|
-
brand: 'stripe',
|
|
102
|
-
url: 'https://mcp.stripe.com',
|
|
103
|
-
auth: 'oauth-or-bearer',
|
|
104
|
-
docsUrl: 'https://docs.stripe.com/mcp',
|
|
105
|
-
verifiedOn: '2026-09-25',
|
|
106
|
-
suggestedSlug: 'stripe',
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
id: 'supabase',
|
|
110
|
-
name: 'Supabase',
|
|
111
|
-
brand: 'supabase',
|
|
112
|
-
url: 'https://mcp.supabase.com/mcp',
|
|
113
|
-
auth: 'oauth-or-bearer',
|
|
114
|
-
docsUrl: 'https://supabase.com/docs/guides/ai-tools/mcp',
|
|
115
|
-
verifiedOn: '2026-09-25',
|
|
116
|
-
suggestedSlug: 'supabase',
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
id: 'vercel',
|
|
120
|
-
name: 'Vercel',
|
|
121
|
-
brand: 'vercel',
|
|
122
|
-
url: 'https://mcp.vercel.com',
|
|
123
|
-
auth: 'oauth',
|
|
124
|
-
docsUrl: 'https://vercel.com/docs/mcp/vercel-mcp',
|
|
125
|
-
verifiedOn: '2026-09-25',
|
|
126
|
-
suggestedSlug: 'vercel',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
id: 'atlassian',
|
|
130
|
-
name: 'Atlassian',
|
|
131
|
-
brand: 'atlassian',
|
|
132
|
-
url: 'https://mcp.atlassian.com/v2/mcp',
|
|
133
|
-
auth: 'oauth-or-bearer',
|
|
134
|
-
docsUrl: 'https://support.atlassian.com/atlassian-rovo-mcp-server/docs/getting-started-with-the-atlassian-remote-mcp-server/',
|
|
135
|
-
verifiedOn: '2026-09-25',
|
|
136
|
-
suggestedSlug: 'atlassian',
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
id: 'asana',
|
|
140
|
-
name: 'Asana',
|
|
141
|
-
brand: 'asana',
|
|
142
|
-
// V2. The V1 Beta server (mcp.asana.com/sse) shut down 2026-08-05.
|
|
143
|
-
url: 'https://mcp.asana.com/v2/mcp',
|
|
144
|
-
auth: 'oauth',
|
|
145
|
-
docsUrl: 'https://developers.asana.com/docs/integrating-with-asanas-mcp-server',
|
|
146
|
-
verifiedOn: '2026-09-25',
|
|
147
|
-
suggestedSlug: 'asana',
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: 'cloudflare',
|
|
151
|
-
name: 'Cloudflare',
|
|
152
|
-
brand: 'cloudflare',
|
|
153
|
-
// The general-purpose one: 2,500+ endpoints across DNS, Workers, R2,
|
|
154
|
-
// Zero Trust. Cloudflare also hosts 16 narrower servers (docs,
|
|
155
|
-
// bindings, observability, ...), not used here.
|
|
156
|
-
url: 'https://mcp.cloudflare.com/mcp',
|
|
157
|
-
auth: 'oauth',
|
|
158
|
-
docsUrl: 'https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/',
|
|
159
|
-
verifiedOn: '2026-09-25',
|
|
160
|
-
suggestedSlug: 'cloudflare',
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
id: 'intercom',
|
|
164
|
-
name: 'Intercom',
|
|
165
|
-
brand: 'intercom',
|
|
166
|
-
url: 'https://mcp.intercom.com/mcp',
|
|
167
|
-
auth: 'oauth-or-bearer',
|
|
168
|
-
docsUrl: 'https://developers.intercom.com/docs/guides/mcp',
|
|
169
|
-
verifiedOn: '2026-09-25',
|
|
170
|
-
suggestedSlug: 'intercom',
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
id: 'hubspot',
|
|
174
|
-
name: 'HubSpot',
|
|
175
|
-
brand: 'hubspot',
|
|
176
|
-
url: 'https://mcp.hubspot.com',
|
|
177
|
-
auth: 'oauth',
|
|
178
|
-
docsUrl: 'https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server',
|
|
179
|
-
verifiedOn: '2026-09-25',
|
|
180
|
-
suggestedSlug: 'hubspot',
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
id: 'netlify',
|
|
184
|
-
name: 'Netlify',
|
|
185
|
-
brand: 'netlify',
|
|
186
|
-
url: 'https://netlify-mcp.netlify.app/mcp',
|
|
187
|
-
auth: 'oauth-or-bearer',
|
|
188
|
-
docsUrl: 'https://docs.netlify.com/build/build-with-ai/netlify-mcp-server/',
|
|
189
|
-
verifiedOn: '2026-09-25',
|
|
190
|
-
suggestedSlug: 'netlify',
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
id: 'neon',
|
|
194
|
-
name: 'Neon',
|
|
195
|
-
brand: 'neon',
|
|
196
|
-
url: 'https://mcp.neon.tech/mcp',
|
|
197
|
-
auth: 'oauth-or-bearer',
|
|
198
|
-
docsUrl: 'https://neon.com/docs/ai/connect-mcp-clients-to-neon',
|
|
199
|
-
verifiedOn: '2026-09-25',
|
|
200
|
-
suggestedSlug: 'neon',
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
id: 'zapier',
|
|
204
|
-
name: 'Zapier',
|
|
205
|
-
brand: 'zapier',
|
|
206
|
-
url: 'https://mcp.zapier.com/api/v1/connect',
|
|
207
|
-
auth: 'oauth-or-bearer',
|
|
208
|
-
docsUrl: 'https://docs.zapier.com/mcp/overview/how-connections-work',
|
|
209
|
-
verifiedOn: '2026-09-25',
|
|
210
|
-
suggestedSlug: 'zapier',
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
id: 'webflow',
|
|
214
|
-
name: 'Webflow',
|
|
215
|
-
brand: 'webflow',
|
|
216
|
-
url: 'https://mcp.webflow.com/mcp',
|
|
217
|
-
auth: 'oauth',
|
|
218
|
-
docsUrl: 'https://developers.webflow.com/mcp/reference/getting-started',
|
|
219
|
-
verifiedOn: '2026-09-25',
|
|
220
|
-
suggestedSlug: 'webflow',
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
id: 'wix',
|
|
224
|
-
name: 'Wix',
|
|
225
|
-
brand: 'wix',
|
|
226
|
-
url: 'https://mcp.wix.com/mcp',
|
|
227
|
-
auth: 'oauth-or-bearer',
|
|
228
|
-
docsUrl: 'https://dev.wix.com/docs/overview/ai-the-wix-platform/the-wix-mcp',
|
|
229
|
-
verifiedOn: '2026-09-25',
|
|
230
|
-
suggestedSlug: 'wix',
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
id: 'gitlab',
|
|
234
|
-
name: 'GitLab',
|
|
235
|
-
brand: 'gitlab',
|
|
236
|
-
// GitLab.com. Self-managed and Dedicated serve the same at https://<host>/api/v4/mcp, which is why the address a
|
|
237
|
-
// catalogue pick fills into the connection form stays editable (owner decision D3). The token is an OAuth one with
|
|
238
|
-
// the `mcp` scope (dynamic client registration) or a fine-grained personal access token with the MCP tool resource;
|
|
239
|
-
// legacy, project and group tokens are refused. On GitLab.com a group owner must allow MCP access for the top-level
|
|
240
|
-
// group first.
|
|
241
|
-
url: 'https://gitlab.com/api/v4/mcp',
|
|
242
|
-
auth: 'oauth-or-bearer',
|
|
243
|
-
docsUrl: 'https://docs.gitlab.com/user/model_context_protocol/mcp_server/',
|
|
244
|
-
verifiedOn: '2026-10-18',
|
|
245
|
-
suggestedSlug: 'gitlab',
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
id: 'gamma',
|
|
249
|
-
name: 'Gamma',
|
|
250
|
-
brand: null,
|
|
251
|
-
// "Uses OAuth with Dynamic Client Registration", on all plans.
|
|
252
|
-
url: 'https://mcp.gamma.app/mcp',
|
|
253
|
-
auth: 'oauth',
|
|
254
|
-
docsUrl: 'https://developers.gamma.app/mcp/gamma-mcp-server',
|
|
255
|
-
verifiedOn: '2026-10-18',
|
|
256
|
-
suggestedSlug: 'gamma',
|
|
257
|
-
},
|
|
258
|
-
];
|
|
259
|
-
//# sourceMappingURL=servers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"servers.js","sourceRoot":"","sources":["../../src/registry/servers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The title and the annotations (MCP `Tool.title`, `ToolAnnotations`) of OnlyMCP's own twenty-eight tools.
|
|
3
|
-
*
|
|
4
|
-
* One table for both ways in: the hosted endpoint sets the same values in its tool files (packages/api/src/mcp/tools,
|
|
5
|
-
* pinned to this table by test/mcp-tool-annotations.spec.ts), and the stdio server lists straight from the copy of this
|
|
6
|
-
* file in packages/mcp (scripts/sync-registry.mjs). A client that decides what to ask about by the hints must see the
|
|
7
|
-
* same answer whichever way it connected. The last two entries, `connection_tool_schema` and `connection_call`, belong
|
|
8
|
-
* to the hosted endpoint alone: they reach the tools of the account's gateway, which the stdio server does not have,
|
|
9
|
-
* so it lists the other twenty-six.
|
|
10
|
-
*
|
|
11
|
-
* What the values say. `readOnlyHint: true` only for the fourteen tools that change nothing. The writers that replace
|
|
12
|
-
* the whole file (`*_write`) are destructive and idempotent. `memory_move` and `connection_create` only add or move,
|
|
13
|
-
* `connection_update` and `connection_tool_toggle` adjust and repeat harmlessly, every `*_delete` is destructive.
|
|
14
|
-
* `connection_call` runs a tool of a foreign server, so it is not read-only, destructive (the callee is unknown) and
|
|
15
|
-
* not idempotent. `openWorldHint` is false for all but `connection_create`, which probes a server of the caller's
|
|
16
|
-
* choosing, and `connection_call`. The hints
|
|
17
|
-
* are hints, not guarantees; the spec asks clients to weigh them by how far they trust the server, and this is that
|
|
18
|
-
* server speaking about itself.
|
|
19
|
-
*/
|
|
20
|
-
export interface ToolHint {
|
|
21
|
-
title: string;
|
|
22
|
-
annotations: {
|
|
23
|
-
readOnlyHint: boolean;
|
|
24
|
-
destructiveHint?: boolean;
|
|
25
|
-
idempotentHint?: boolean;
|
|
26
|
-
openWorldHint: boolean;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export declare const TOOL_HINTS: Readonly<Record<string, ToolHint>>;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const reads = (title) => ({ title, annotations: { readOnlyHint: true, openWorldHint: false } });
|
|
2
|
-
const writes = (title, how) => ({
|
|
3
|
-
title,
|
|
4
|
-
annotations: {
|
|
5
|
-
readOnlyHint: false,
|
|
6
|
-
destructiveHint: how.destructive,
|
|
7
|
-
idempotentHint: how.idempotent,
|
|
8
|
-
openWorldHint: how.openWorld ?? false,
|
|
9
|
-
},
|
|
10
|
-
});
|
|
11
|
-
export const TOOL_HINTS = {
|
|
12
|
-
list_memory: reads('List memory files'),
|
|
13
|
-
memory_read: reads('Read a memory file'),
|
|
14
|
-
memory_write: writes('Write a memory file', { destructive: true, idempotent: true }),
|
|
15
|
-
memory_delete: writes('Delete a memory file', { destructive: true, idempotent: false }),
|
|
16
|
-
memory_search: reads('Search memory'),
|
|
17
|
-
memory_tree: reads('Show the memory tree'),
|
|
18
|
-
memory_move: writes('Move a memory file or folder', { destructive: false, idempotent: false }),
|
|
19
|
-
memory_links: reads('Show memory links'),
|
|
20
|
-
list_skills: reads('List skills'),
|
|
21
|
-
get_skill: reads('Load a skill'),
|
|
22
|
-
skill_write: writes('Write a skill', { destructive: true, idempotent: true }),
|
|
23
|
-
skill_delete: writes('Delete a skill', { destructive: true, idempotent: false }),
|
|
24
|
-
list_skill_files: reads('List skill files'),
|
|
25
|
-
get_skill_file: reads('Read a skill file'),
|
|
26
|
-
skill_file_write: writes('Write a skill file', { destructive: true, idempotent: true }),
|
|
27
|
-
skill_file_delete: writes('Delete a skill file', { destructive: true, idempotent: false }),
|
|
28
|
-
list_agents: reads('List agents'),
|
|
29
|
-
get_agent_definition: reads('Load an agent definition'),
|
|
30
|
-
agent_write: writes('Write an agent', { destructive: true, idempotent: true }),
|
|
31
|
-
agent_delete: writes('Delete an agent', { destructive: true, idempotent: false }),
|
|
32
|
-
list_connections: reads('List connections'),
|
|
33
|
-
connection_create: writes('Add a connection', { destructive: false, idempotent: false, openWorld: true }),
|
|
34
|
-
connection_update: writes('Update a connection', { destructive: false, idempotent: true }),
|
|
35
|
-
connection_delete: writes('Delete a connection', { destructive: true, idempotent: false }),
|
|
36
|
-
connection_tools: reads("List a connection's tools"),
|
|
37
|
-
connection_tool_toggle: writes('Switch a connection tool on or off', { destructive: false, idempotent: true }),
|
|
38
|
-
connection_tool_schema: reads("Show a connection tool's schema"),
|
|
39
|
-
connection_call: writes('Call a connection tool', { destructive: true, idempotent: false, openWorld: true }),
|
|
40
|
-
};
|
|
41
|
-
//# sourceMappingURL=toolHints.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toolHints.js","sourceRoot":"","sources":["../../src/registry/toolHints.ts"],"names":[],"mappings":"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"}
|
package/dist/registry/types.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
export type ClientId = 'claude-code' | 'claude-app' | 'chatgpt' | 'codex' | 'antigravity' | 'gemini-app' | 'grok' | 'copilot-vscode' | 'cursor' | 'windsurf' | 'cline' | 'zed' | 'continue' | 'gitlab-duo' | 'opencode';
|
|
2
|
-
export type ClientCategory = 'chat' | 'coding' | 'ide';
|
|
3
|
-
/** How this client can reach OnlyMCP. Order in the array is preference order. */
|
|
4
|
-
export type ConnectMethod = 'remote-oauth' | 'remote-header' | 'stdio';
|
|
5
|
-
export type SnippetLanguage = 'bash' | 'json' | 'toml' | 'yaml' | 'text';
|
|
6
|
-
export interface Snippet {
|
|
7
|
-
language: SnippetLanguage;
|
|
8
|
-
/** Never translated, never localised, never contains a placeholder path. */
|
|
9
|
-
text: string;
|
|
10
|
-
/** Where the snippet goes, if it is a file. */
|
|
11
|
-
path?: string;
|
|
12
|
-
}
|
|
13
|
-
/** Present only where `npx onlymcp install` can write the config itself. */
|
|
14
|
-
export interface ClientInstall {
|
|
15
|
-
configPath: string;
|
|
16
|
-
format: 'json' | 'toml';
|
|
17
|
-
stubDir: string | null;
|
|
18
|
-
}
|
|
19
|
-
export interface ClientRecord {
|
|
20
|
-
id: ClientId;
|
|
21
|
-
/**
|
|
22
|
-
* Retired ids and spellings that still mean this client, so an old link (`?client=gemini-cli`) or an old command
|
|
23
|
-
* (`install --client gemini-cli`) lands on the successor. An alias is never another record's id (snippets.spec.ts).
|
|
24
|
-
*/
|
|
25
|
-
aliases?: readonly string[];
|
|
26
|
-
name: string;
|
|
27
|
-
category: ClientCategory;
|
|
28
|
-
/**
|
|
29
|
-
* simple-icons slug, or a key of `FILE_MARKS` in `web/src/components/BrandMark.tsx` (an owner's official file, shown
|
|
30
|
-
* under their brand guidelines: `openai`, `antigravity`, `grok`), or null when no mark may be used.
|
|
31
|
-
*/
|
|
32
|
-
brand: string | null;
|
|
33
|
-
methods: ConnectMethod[];
|
|
34
|
-
docsUrl: string;
|
|
35
|
-
/** ISO date on which the facts below were checked against docsUrl. */
|
|
36
|
-
verifiedOn: string;
|
|
37
|
-
/** Keys into CAVEATS (caveats.ts) for restrictions that must be stated; empty when there are none. */
|
|
38
|
-
caveats: string[];
|
|
39
|
-
install: ClientInstall | null;
|
|
40
|
-
/**
|
|
41
|
-
* The hosts a web client's OAuth redirect_uri points at, as its docs name them or, where they name none, as its own
|
|
42
|
-
* registrations on only-mcp.com show. The consent page shows this client's mark for a request whose code goes there:
|
|
43
|
-
* the redirect is used, not claimed. Absent where nothing is verified.
|
|
44
|
-
*/
|
|
45
|
-
oauthRedirectHosts?: readonly string[];
|
|
46
|
-
/** Pure generator. Returns null when the remote-header method does not apply. */
|
|
47
|
-
remote(ctx: RemoteContext): Snippet[] | null;
|
|
48
|
-
}
|
|
49
|
-
export interface RemoteContext {
|
|
50
|
-
/** https://only-mcp.com/api/mcp */
|
|
51
|
-
endpoint: string;
|
|
52
|
-
/** Real token, or the literal placeholder 'omk_...'. */
|
|
53
|
-
token: string;
|
|
54
|
-
/** '~' on posix, '%USERPROFILE%' on windows. */
|
|
55
|
-
homePlaceholder?: string;
|
|
56
|
-
}
|
|
57
|
-
export interface ServerRecord {
|
|
58
|
-
id: string;
|
|
59
|
-
name: string;
|
|
60
|
-
/**
|
|
61
|
-
* simple-icons slug, or a key of `FILE_MARKS` in `web/src/components/BrandMark.tsx` (an owner's official file, shown
|
|
62
|
-
* under their brand guidelines: `openai`), or null when no mark may be used.
|
|
63
|
-
*/
|
|
64
|
-
brand: string | null;
|
|
65
|
-
url: string;
|
|
66
|
-
auth: 'oauth' | 'bearer' | 'oauth-or-bearer' | 'none';
|
|
67
|
-
docsUrl: string;
|
|
68
|
-
verifiedOn: string;
|
|
69
|
-
/** 'github' -> github__create_issue */
|
|
70
|
-
suggestedSlug: string;
|
|
71
|
-
}
|
package/dist/registry/types.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// Generated by scripts/sync-registry.mjs. Do not edit.
|
|
2
|
-
// Types for the client and server registry. Zero runtime dependencies, no
|
|
3
|
-
// Node API, no DOM, no React: this package is imported by the API (server),
|
|
4
|
-
// the web app (browser) and, as a generated copy, the published CLI.
|
|
5
|
-
export {};
|
|
6
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,0EAA0E;AAC1E,4EAA4E;AAC5E,qEAAqE"}
|
package/dist/skillFilePath.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function isSafeSkillFilePath(path: string): boolean;
|
package/dist/skillFilePath.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// Client-seitige Kopie der Server-Regel (packages/api/src/skills/files.ts,
|
|
2
|
-
// skillFilePath). Dasselbe Muster wie memoryPath.ts, und aus zwei Gruenden:
|
|
3
|
-
//
|
|
4
|
-
// Beim Schreiben (stubs.ts) ist es eine Sicherheitspruefung - aus einem Pfad,
|
|
5
|
-
// den der Server geschickt hat, wird ein echter Schreibvorgang auf einer
|
|
6
|
-
// echten Platte, und die muss auch dann halten, wenn jede andere Pruefung
|
|
7
|
-
// versagt hat.
|
|
8
|
-
//
|
|
9
|
-
// Beim Planen (import/plan.ts) ist es Hoeflichkeit: der Bericht soll
|
|
10
|
-
// "uebersprungen, ungueltiger Pfad" sagen koennen, statt dass jemand 307
|
|
11
|
-
// Uploads zuschaut und einen 400 am Ende. Gemessen an einem echten Setup war
|
|
12
|
-
// das genau eine Datei, `ui-styling/scripts/.coverage` - ein Segment darf
|
|
13
|
-
// nicht mit einem Punkt beginnen.
|
|
14
|
-
const SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
15
|
-
const MAX_SEGMENTS = 8;
|
|
16
|
-
const MAX_LENGTH = 200;
|
|
17
|
-
export function isSafeSkillFilePath(path) {
|
|
18
|
-
if (path.length === 0 || path.length > MAX_LENGTH)
|
|
19
|
-
return false;
|
|
20
|
-
// SKILL.md ist der Inhalt des Skills selbst und keine Begleitdatei. Der
|
|
21
|
-
// Server lehnt sie ab, damit es nicht zwei Orte fuer denselben Text gibt.
|
|
22
|
-
if (path === 'SKILL.md')
|
|
23
|
-
return false;
|
|
24
|
-
const parts = path.split('/');
|
|
25
|
-
if (parts.length > MAX_SEGMENTS)
|
|
26
|
-
return false;
|
|
27
|
-
return parts.every((seg) => SEGMENT.test(seg) && seg !== '..' && seg !== '.');
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=skillFilePath.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skillFilePath.js","sourceRoot":"","sources":["../src/skillFilePath.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,0EAA0E;AAC1E,eAAe;AACf,EAAE;AACF,qEAAqE;AACrE,yEAAyE;AACzE,6EAA6E;AAC7E,0EAA0E;AAC1E,kCAAkC;AAClC,MAAM,OAAO,GAAG,8BAA8B,CAAC;AAC/C,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU;QAAE,OAAO,KAAK,CAAC;IAChE,wEAAwE;IACxE,0EAA0E;IAC1E,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,YAAY;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;AAChF,CAAC"}
|
package/dist/stubs.d.ts
DELETED
package/dist/stubs.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { headerField, headerOf } from './import/frontmatter.js';
|
|
4
|
-
// Der Client prueft den Pfad, den der Server geschickt hat, unabhaengig davon,
|
|
5
|
-
// dass der Server ihn beim Schreiben schon geprueft hat: hier wird aus einem
|
|
6
|
-
// Pfad ein echter Schreibvorgang auf einer echten Platte.
|
|
7
|
-
import { isSafeSkillFilePath } from './skillFilePath.js';
|
|
8
|
-
// Gleiche Positivliste wie server-seitig (packages/api/src/http/names.ts,
|
|
9
|
-
// skillName/agentName). Dieses Paket haengt nicht von @onlymcp/api ab, also
|
|
10
|
-
// keine gemeinsame Konstante, aber ein Name, der so nie in der Datenbank
|
|
11
|
-
// entstehen sollte, darf trotzdem nie als Pfadsegment landen: ein falsch
|
|
12
|
-
// konfiguriertes oder kompromittiertes ONLYMCP_API_URL soll niemals Dateien
|
|
13
|
-
// ausserhalb von `dir` schreiben koennen, egal was der Server zurueckgibt.
|
|
14
|
-
const SAFE_AGENT_NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
15
|
-
// Skills duerfen seit Aufgabe 11 einen Namensraum tragen.
|
|
16
|
-
const SAFE_SKILL_NAME = /^[a-z0-9]+(-[a-z0-9]+)*(:[a-z0-9]+(-[a-z0-9]+)*)?$/;
|
|
17
|
-
/**
|
|
18
|
-
* Das Merkmal, an dem `collect` einen Stub wiedererkennt.
|
|
19
|
-
*
|
|
20
|
-
* Es ist der Grund, warum Stubs ueberhaupt in `~/.claude/skills` liegen
|
|
21
|
-
* duerfen: ohne dieses Feld laedt der naechste `onlymcp import` jeden
|
|
22
|
-
* Platzhalter als Skill hoch und ersetzt damit den echten Inhalt durch den
|
|
23
|
-
* Satz "ruf get_skill auf".
|
|
24
|
-
*/
|
|
25
|
-
const MARKER = 'x-onlymcp-stub';
|
|
26
|
-
/**
|
|
27
|
-
* Der Ordnername eines Stubs.
|
|
28
|
-
*
|
|
29
|
-
* Ein Skill kann `superpowers:brainstorming` heissen, ein Ordner auf einer
|
|
30
|
-
* Windows-Platte kann keinen Doppelpunkt tragen, und der Scanner eines
|
|
31
|
-
* Clients erwartet ohnehin, dass `name:` zum Ordner passt. Der Stub heisst
|
|
32
|
-
* deshalb lokal `superpowers-brainstorming` und ruft im Text den echten
|
|
33
|
-
* Namen auf. `x-onlymcp-name` haelt fest, welcher das ist - daran erkennt
|
|
34
|
-
* der naechste Lauf, ob der Ordner ihm gehoert oder einem anderen Skill.
|
|
35
|
-
*/
|
|
36
|
-
function stubDirName(name) {
|
|
37
|
-
return name.replace(/:/g, '-');
|
|
38
|
-
}
|
|
39
|
-
// Frontmatter ist YAML, aber die Werte (description, model, jeder Tool-Name)
|
|
40
|
-
// kommen ungeprueft vom Server. Ein Wert mit Zeilenumbruch koennte sonst aus
|
|
41
|
-
// seiner eigenen Zeile ausbrechen und zusaetzliche Frontmatter-Felder
|
|
42
|
-
// einschleusen (z.B. ein erfundenes weiteres `tools:`). Zeilenumbrueche
|
|
43
|
-
// werden deshalb entfernt, nicht escaped: ein Skill-/Agent-Name oder eine
|
|
44
|
-
// Beschreibung braucht nie einen Zeilenumbruch, um sinnvoll zu sein.
|
|
45
|
-
function yamlSafe(value) {
|
|
46
|
-
return (value ?? '').replace(/[\r\n]+/g, ' ').trim();
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Darf an diese Stelle geschrieben werden?
|
|
50
|
-
*
|
|
51
|
-
* Seit Aufgabe 12 liegen die Stubs in `~/.claude/skills` und `~/.codex/skills`
|
|
52
|
-
* - denselben Ordnern, aus denen importiert wird. Eine bestehende Datei, die
|
|
53
|
-
* kein Stub ist, ist die echte Arbeit eines Menschen und wird nicht
|
|
54
|
-
* ueberschrieben. Gehoert ein vorhandener Stub einem anderen Skill (zwei
|
|
55
|
-
* Plugins mit demselben Skill-Namen ergeben denselben Ordnernamen), bleibt
|
|
56
|
-
* ebenfalls stehen, was da ist: der erste hat ihn, der zweite wird gemeldet.
|
|
57
|
-
*/
|
|
58
|
-
async function mayWrite(path, owner) {
|
|
59
|
-
let existing;
|
|
60
|
-
try {
|
|
61
|
-
existing = await readFile(path, 'utf8');
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return true; // nicht da, also frei
|
|
65
|
-
}
|
|
66
|
-
const head = headerOf(existing);
|
|
67
|
-
if (head === null || headerField(head, MARKER) !== 'true')
|
|
68
|
-
return false;
|
|
69
|
-
const mine = headerField(head, 'x-onlymcp-name');
|
|
70
|
-
return mine === undefined || mine === owner;
|
|
71
|
-
}
|
|
72
|
-
export async function writeStubs(api, dir) {
|
|
73
|
-
const [{ skills }, { agents }] = await Promise.all([api.listSkills(), api.listAgents()]);
|
|
74
|
-
let files = 0;
|
|
75
|
-
let written = 0;
|
|
76
|
-
/** Was stehen geblieben ist, weil dort schon etwas Echtes lag. */
|
|
77
|
-
const kept = [];
|
|
78
|
-
for (const s of skills) {
|
|
79
|
-
if (!SAFE_SKILL_NAME.test(s.name))
|
|
80
|
-
continue;
|
|
81
|
-
const target = join(dir, 'skills', stubDirName(s.name));
|
|
82
|
-
const skillMd = join(target, 'SKILL.md');
|
|
83
|
-
if (!(await mayWrite(skillMd, s.name))) {
|
|
84
|
-
// Auch die Begleitdateien bleiben aus: sie in einen fremden Skill-Ordner
|
|
85
|
-
// zu legen machte aus einer geschonten Datei einen halb ueberschriebenen
|
|
86
|
-
// Ordner.
|
|
87
|
-
kept.push(`skills/${stubDirName(s.name)}`);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
await mkdir(target, { recursive: true });
|
|
91
|
-
await writeFile(skillMd, `---
|
|
92
|
-
name: ${stubDirName(s.name)}
|
|
93
|
-
description: ${yamlSafe(s.description) || 'Synchronisiert ueber OnlyMCP. Inhalt wird bei Bedarf geladen.'}
|
|
94
|
-
${MARKER}: true
|
|
95
|
-
x-onlymcp-name: ${s.name}
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
Call \`get_skill({ name: "${s.name}" })\` on the OnlyMCP server and follow whatever comes back.
|
|
99
|
-
`, 'utf8');
|
|
100
|
-
written += 1;
|
|
101
|
-
// Die Begleitdateien liegen danach WIRKLICH auf der Platte, nicht hinter
|
|
102
|
-
// einem Werkzeug. Genau das macht das Merkmal aus: ein Skill, dessen Text
|
|
103
|
-
// "lies references/palette.md" sagt, funktioniert unveraendert, weil die
|
|
104
|
-
// Datei da ist. Nur die SKILL.md bleibt ein Stub - sie ist die einzige,
|
|
105
|
-
// die jeder Client ohnehin zuerst liest, und der Sparsinn des Verfahrens
|
|
106
|
-
// haengt an ihr.
|
|
107
|
-
//
|
|
108
|
-
// Faellt der Abruf aus, bleibt der Stub trotzdem stehen: ein Client, der
|
|
109
|
-
// den Server gerade nicht erreicht, soll wenigstens wissen, dass es den
|
|
110
|
-
// Skill gibt.
|
|
111
|
-
try {
|
|
112
|
-
const detail = await api.getSkill(s.name);
|
|
113
|
-
for (const meta of detail.files ?? []) {
|
|
114
|
-
if (!isSafeSkillFilePath(meta.path))
|
|
115
|
-
continue;
|
|
116
|
-
const file = await api.getSkillFile(s.name, meta.path);
|
|
117
|
-
const dest = join(target, ...meta.path.split('/'));
|
|
118
|
-
await mkdir(dirname(dest), { recursive: true });
|
|
119
|
-
if (file.encoding === 'base64') {
|
|
120
|
-
await writeFile(dest, Buffer.from(file.content, 'base64'));
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
await writeFile(dest, file.content, 'utf8');
|
|
124
|
-
}
|
|
125
|
-
files += 1;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// absichtlich still, siehe oben
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
await mkdir(join(dir, 'agents'), { recursive: true });
|
|
133
|
-
let agentsWritten = 0;
|
|
134
|
-
for (const a of agents) {
|
|
135
|
-
if (!SAFE_AGENT_NAME.test(a.name))
|
|
136
|
-
continue;
|
|
137
|
-
const dest = join(dir, 'agents', `${a.name}.md`);
|
|
138
|
-
if (!(await mayWrite(dest, a.name))) {
|
|
139
|
-
kept.push(`agents/${a.name}.md`);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const description = yamlSafe(a.description);
|
|
143
|
-
const model = a.model ? yamlSafe(a.model) : '';
|
|
144
|
-
const tools = a.tools.map(yamlSafe).join(', ');
|
|
145
|
-
await writeFile(dest, `---
|
|
146
|
-
name: ${a.name}
|
|
147
|
-
description: ${description}
|
|
148
|
-
${model ? `model: ${model}\n` : ''}tools: ${tools}
|
|
149
|
-
${MARKER}: true
|
|
150
|
-
x-onlymcp-name: ${a.name}
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
Call \`get_agent_definition({ name: "${a.name}" })\` on the OnlyMCP server and follow whatever comes back.
|
|
154
|
-
`, 'utf8');
|
|
155
|
-
agentsWritten += 1;
|
|
156
|
-
}
|
|
157
|
-
return { skills: written, agents: agentsWritten, files, kept };
|
|
158
|
-
}
|
|
159
|
-
//# sourceMappingURL=stubs.js.map
|
package/dist/stubs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stubs.js","sourceRoot":"","sources":["../src/stubs.ts"],"names":[],"mappings":"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"}
|