@perenia/mcp 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,6 +41,7 @@ against a dev instance).
41
41
  | `open_in_perenia` | Turns the same filters as `search_companies` into the URL of that search in the web app — the link to hand to a person. |
42
42
  | `list_columns` | The column catalogue for `columns`, grouped, with each column's kind and fields. No quota cost. |
43
43
  | `get_usage` | Today's quota for your key (used / limit / remaining / reset) and the per-minute rate limit. Every other tool result already ends with the same `quota` figures. |
44
+ | `get_lists` · `get_list_contents` · `create_list` · `add_to_list` | Your lists in the Perenia app: read them (member SIRENs in display order), create one, add companies by SIREN (idempotent, unknown SIRENs reported). Need a key **bound to your Perenia user** with the `lists` scope — ask your Perenia contact; an unbound key gets `key_not_bound`. |
44
45
 
45
46
  Every result carries `perenia_url` per company (the company page in the app).
46
47
  `PERENIA_APP_URL` overrides the app origin those links use.
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ if (!apiKey) {
11
11
  }
12
12
  const baseUrl = (process.env.PERENIA_API_URL ?? 'https://api.perenia.ai').replace(/\/$/, '');
13
13
  const appUrl = (process.env.PERENIA_APP_URL ?? 'https://app.perenia.ai').replace(/\/$/, '');
14
- const server = new McpServer({ name: 'perenia', version: '0.3.0' });
14
+ const server = new McpServer({ name: 'perenia', version: '0.4.0' });
15
15
  registerTools(server, new ApiClient({ baseUrl, apiKey }), { appUrl });
16
16
  await server.connect(new StdioServerTransport());
17
17
  console.error(`perenia-mcp ready (${baseUrl})`);
package/dist/tools.js CHANGED
@@ -153,6 +153,28 @@ export function registerTools(server, api, opts) {
153
153
  (groups[group] ??= []).push(column);
154
154
  return ok({ groups });
155
155
  }));
156
+ // ---- Lists: the user's own objects. Need a key bound to a Perenia user
157
+ // (the API answers 403 key_not_bound otherwise) and the `lists` scope.
158
+ const listIdParam = z.string().uuid().describe('List id, from get_lists');
159
+ server.registerTool('get_lists', {
160
+ description: "The user's lists in the Perenia app (default list first) with member counts. Needs an API key bound to a Perenia user; otherwise the error says key_not_bound.",
161
+ inputSchema: {},
162
+ }, () => guarded(async () => {
163
+ const res = (await api.get('/v1/lists'));
164
+ return ok({ lists: res.data });
165
+ }));
166
+ server.registerTool('get_list_contents', {
167
+ description: 'One list with its member SIRENs in display order. Pass them to get_companies (100 at a time) for the data, or to search_companies as exclude_list_ids to dedupe against the list.',
168
+ inputSchema: { list_id: listIdParam },
169
+ }, ({ list_id }) => guarded(async () => ok((await api.get(`/v1/lists/${list_id}`)))));
170
+ server.registerTool('create_list', {
171
+ description: 'Create an empty list in the Perenia app for the user (name 1–100 characters). Returns the list with its id.',
172
+ inputSchema: { name: z.string().min(1).max(100) },
173
+ }, ({ name }) => guarded(async () => ok((await api.post('/v1/lists', { name })))));
174
+ server.registerTool('add_to_list', {
175
+ description: 'Add companies to a list by SIREN (1–10,000 per call, idempotent). Returns which SIRENs were added, which were already in the list, and which Perenia does not know.',
176
+ inputSchema: { list_id: listIdParam, sirens: z.array(sirenParam).min(1).max(10_000) },
177
+ }, ({ list_id, sirens }) => guarded(async () => ok((await api.post(`/v1/lists/${list_id}/companies`, { sirens })))));
156
178
  server.registerTool('open_in_perenia', {
157
179
  description: 'Hand a search to a person: the same filters as search_companies become the URL of that search in the Perenia web app (live results, facets, export, lists). Returns the link — give it to the user. A geographic radius (lat/lng) has no URL form and is dropped.',
158
180
  inputSchema: { ...searchFiltersShape },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perenia/mcp",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for the Perenia Partner API — search and analyze French companies from any MCP client",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",