@mnicole-dev/pappers-mcp-server 1.0.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 +21 -0
- package/README.md +101 -0
- package/dist/index.js +284 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maxime Nicole
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Pappers MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@mnicole-dev/pappers-mcp-server)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
MCP (Model Context Protocol) server for the [Pappers API](https://www.pappers.fr/api) — official information about French companies (SIREN / SIRET / financial data / officers / public records).
|
|
7
|
+
|
|
8
|
+
Lets an MCP client (Claude Desktop, Claude Code, Cursor, etc.) search and fetch up-to-date legal and financial data on French entities.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
No install needed — run on demand via `npx`. The MCP client launches it as a child process and pipes JSON-RPC over stdio.
|
|
13
|
+
|
|
14
|
+
## Configuration
|
|
15
|
+
|
|
16
|
+
One environment variable required :
|
|
17
|
+
|
|
18
|
+
| Variable | Description |
|
|
19
|
+
|----------|-------------|
|
|
20
|
+
| `PAPPERS_API_TOKEN` | API key from your Pappers account (see [pappers.fr/api](https://www.pappers.fr/api)) |
|
|
21
|
+
|
|
22
|
+
### Claude Code (or Claude Desktop)
|
|
23
|
+
|
|
24
|
+
Edit your MCP servers configuration (`~/.claude.json` for Claude Code, `~/Library/Application Support/Claude/claude_desktop_config.json` for Claude Desktop) and add :
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"pappers": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@mnicole-dev/pappers-mcp-server"],
|
|
32
|
+
"env": {
|
|
33
|
+
"PAPPERS_API_TOKEN": "your-api-token"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Restart your MCP client.
|
|
41
|
+
|
|
42
|
+
### Cursor
|
|
43
|
+
|
|
44
|
+
Add to `.cursor/mcp.json` (project-level) or global Cursor settings :
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"pappers": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@mnicole-dev/pappers-mcp-server"],
|
|
52
|
+
"env": {
|
|
53
|
+
"PAPPERS_API_TOKEN": "your-api-token"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Available tools
|
|
61
|
+
|
|
62
|
+
| Tool | Description |
|
|
63
|
+
|------|-------------|
|
|
64
|
+
| `search-company` | Search for French companies by name, SIREN or SIRET |
|
|
65
|
+
| `get-company` | Fetch detailed info on a company (legal form, officers, address, activity codes) |
|
|
66
|
+
| `get-finances` | Fetch up to 3 years of financial statements (revenue, net profit, equity, headcount) |
|
|
67
|
+
| `get-dirigeants` | List active officers and directors of a company |
|
|
68
|
+
| `search-dirigeant` | Search for officers by name |
|
|
69
|
+
|
|
70
|
+
All tools accept friendly arguments validated via [Zod](https://github.com/colinhacks/zod).
|
|
71
|
+
|
|
72
|
+
## Local development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/mnicole90/pappers-mcp-server.git
|
|
76
|
+
cd pappers-mcp-server
|
|
77
|
+
npm install
|
|
78
|
+
npm run build
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
To run locally with an MCP client during development :
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
node dist/index.js
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The server communicates over stdio.
|
|
88
|
+
|
|
89
|
+
## API rate limits
|
|
90
|
+
|
|
91
|
+
Pappers free tier : 100 requests / day.
|
|
92
|
+
|
|
93
|
+
Paid plans give higher quotas — see [pappers.fr/api/tarifs](https://www.pappers.fr/api/tarifs).
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT — see [LICENSE](LICENSE).
|
|
98
|
+
|
|
99
|
+
## Author
|
|
100
|
+
|
|
101
|
+
[Maxime Nicole](https://github.com/mnicole90) — [KodeSaaS](https://kodesaas.com)
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var BASE_URL = "https://api.pappers.fr/v2";
|
|
8
|
+
function getApiToken() {
|
|
9
|
+
const token = process.env["PAPPERS_API_TOKEN"];
|
|
10
|
+
if (!token) throw new Error("PAPPERS_API_TOKEN environment variable is required");
|
|
11
|
+
return token;
|
|
12
|
+
}
|
|
13
|
+
async function pappers(endpoint, params) {
|
|
14
|
+
const url = new URL(`${BASE_URL}${endpoint}`);
|
|
15
|
+
url.searchParams.set("api_token", getApiToken());
|
|
16
|
+
for (const [k, v] of Object.entries(params)) {
|
|
17
|
+
if (v) url.searchParams.set(k, v);
|
|
18
|
+
}
|
|
19
|
+
const resp = await fetch(url.toString());
|
|
20
|
+
if (!resp.ok) throw new Error(`Pappers API error ${resp.status}: ${await resp.text()}`);
|
|
21
|
+
return resp.json();
|
|
22
|
+
}
|
|
23
|
+
function textResult(text) {
|
|
24
|
+
return { content: [{ type: "text", text }] };
|
|
25
|
+
}
|
|
26
|
+
var server = new McpServer({
|
|
27
|
+
name: "pappers-mcp-server",
|
|
28
|
+
version: "1.0.0"
|
|
29
|
+
});
|
|
30
|
+
server.tool(
|
|
31
|
+
"search-company",
|
|
32
|
+
"Search for French companies by name, NAF code, department, region or workforce range.",
|
|
33
|
+
{
|
|
34
|
+
q: z.string().describe("Search query (company name, SIREN, etc.)"),
|
|
35
|
+
code_naf: z.string().default("").describe('NAF code filter (e.g. "6201Z")'),
|
|
36
|
+
departement: z.string().default("").describe('Department number filter (e.g. "75")'),
|
|
37
|
+
region: z.string().default("").describe('Region filter (e.g. "Ile-de-France")'),
|
|
38
|
+
tranche_effectif: z.string().default("").describe("Workforce range filter"),
|
|
39
|
+
page: z.string().default("1").describe("Page number (default 1)"),
|
|
40
|
+
par_page: z.string().default("10").describe("Results per page (default 10, max 100)")
|
|
41
|
+
},
|
|
42
|
+
async (params) => {
|
|
43
|
+
const data = await pappers("/recherche", {
|
|
44
|
+
q: params.q,
|
|
45
|
+
code_naf: params.code_naf,
|
|
46
|
+
departement: params.departement,
|
|
47
|
+
region: params.region,
|
|
48
|
+
tranche_effectif: params.tranche_effectif,
|
|
49
|
+
page: params.page,
|
|
50
|
+
par_page: params.par_page,
|
|
51
|
+
champs_supplementaires: "sites_internet,telephone,email"
|
|
52
|
+
});
|
|
53
|
+
if (!data.resultats?.length) {
|
|
54
|
+
return textResult("Aucun resultat trouve.");
|
|
55
|
+
}
|
|
56
|
+
const lines = [`**${data.total} resultats** (page ${data.page})
|
|
57
|
+
`];
|
|
58
|
+
for (const e of data.resultats) {
|
|
59
|
+
const parts = [`### ${e.nom_entreprise}`, `SIREN: ${e.siren}`];
|
|
60
|
+
if (e.siege?.siret) parts.push(`SIRET siege: ${e.siege.siret}`);
|
|
61
|
+
if (e.siege) {
|
|
62
|
+
const addr = [e.siege.adresse_ligne_1, e.siege.code_postal, e.siege.ville].filter(Boolean).join(" ");
|
|
63
|
+
if (addr) parts.push(`Adresse: ${addr}`);
|
|
64
|
+
}
|
|
65
|
+
if (e.code_naf) parts.push(`NAF: ${e.code_naf} - ${e.libelle_code_naf || ""}`);
|
|
66
|
+
if (e.tranche_effectif) parts.push(`Effectif: ${e.tranche_effectif}`);
|
|
67
|
+
if (e.dirigeants?.length) {
|
|
68
|
+
const dirs = e.dirigeants.map((d) => `${d.prenom || ""} ${d.nom || ""} (${d.qualite || ""})`.trim()).join(", ");
|
|
69
|
+
parts.push(`Dirigeants: ${dirs}`);
|
|
70
|
+
}
|
|
71
|
+
if (e.sites_internet?.length) {
|
|
72
|
+
parts.push(`Site web: ${e.sites_internet.map((s) => s.url).join(", ")}`);
|
|
73
|
+
}
|
|
74
|
+
if (e.telephone) parts.push(`Telephone: ${e.telephone}`);
|
|
75
|
+
if (e.email) parts.push(`Email: ${e.email}`);
|
|
76
|
+
lines.push(parts.join("\n"));
|
|
77
|
+
}
|
|
78
|
+
return textResult(lines.join("\n\n"));
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
server.tool(
|
|
82
|
+
"get-company",
|
|
83
|
+
"Get detailed information about a French company by SIREN or SIRET number.",
|
|
84
|
+
{
|
|
85
|
+
siren: z.string().default("").describe("SIREN number (9 digits)"),
|
|
86
|
+
siret: z.string().default("").describe("SIRET number (14 digits). Use either siren or siret.")
|
|
87
|
+
},
|
|
88
|
+
async (params) => {
|
|
89
|
+
if (!params.siren && !params.siret) {
|
|
90
|
+
return textResult("Erreur: vous devez fournir un SIREN ou un SIRET.");
|
|
91
|
+
}
|
|
92
|
+
const queryParams = {
|
|
93
|
+
champs_supplementaires: "sites_internet,telephone,email,lien_linkedin"
|
|
94
|
+
};
|
|
95
|
+
if (params.siret) {
|
|
96
|
+
queryParams.siret = params.siret;
|
|
97
|
+
} else {
|
|
98
|
+
queryParams.siren = params.siren;
|
|
99
|
+
}
|
|
100
|
+
const data = await pappers("/entreprise", queryParams);
|
|
101
|
+
const lines = [`# ${data.nom_entreprise}`];
|
|
102
|
+
lines.push(`**SIREN:** ${data.siren}`);
|
|
103
|
+
if (data.siege?.siret) lines.push(`**SIRET siege:** ${data.siege.siret}`);
|
|
104
|
+
if (data.forme_juridique) lines.push(`**Forme juridique:** ${data.forme_juridique}`);
|
|
105
|
+
if (data.date_creation_formate || data.date_creation) {
|
|
106
|
+
lines.push(`**Date de creation:** ${data.date_creation_formate || data.date_creation}`);
|
|
107
|
+
}
|
|
108
|
+
if (data.code_naf) {
|
|
109
|
+
lines.push(`**Code NAF:** ${data.code_naf} - ${data.libelle_code_naf || ""}`);
|
|
110
|
+
}
|
|
111
|
+
if (data.objet_social) lines.push(`**Objet social:** ${data.objet_social}`);
|
|
112
|
+
if (data.siege) {
|
|
113
|
+
const addr = [
|
|
114
|
+
data.siege.adresse_ligne_1,
|
|
115
|
+
data.siege.adresse_ligne_2,
|
|
116
|
+
data.siege.code_postal,
|
|
117
|
+
data.siege.ville,
|
|
118
|
+
data.siege.pays
|
|
119
|
+
].filter(Boolean).join(" ");
|
|
120
|
+
if (addr) lines.push(`**Adresse:** ${addr}`);
|
|
121
|
+
}
|
|
122
|
+
if (data.tranche_effectif || data.effectif) {
|
|
123
|
+
lines.push(`**Effectif:** ${data.effectif || data.tranche_effectif}`);
|
|
124
|
+
}
|
|
125
|
+
if (data.capital_formate || data.capital) {
|
|
126
|
+
lines.push(`**Capital social:** ${data.capital_formate || `${data.capital} EUR`}`);
|
|
127
|
+
}
|
|
128
|
+
if (data.representants?.length) {
|
|
129
|
+
lines.push("\n**Dirigeants:**");
|
|
130
|
+
for (const d of data.representants) {
|
|
131
|
+
if (d.personne_morale && d.denomination) {
|
|
132
|
+
lines.push(`- ${d.denomination} (${d.qualite || "N/A"})`);
|
|
133
|
+
} else {
|
|
134
|
+
const name = d.nom_complet || `${d.prenom || ""} ${d.nom || ""}`.trim();
|
|
135
|
+
lines.push(`- ${name} (${d.qualite || "N/A"})`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (data.sites_internet?.length) {
|
|
140
|
+
lines.push(`
|
|
141
|
+
**Site(s) web:** ${data.sites_internet.map((s) => s.url).join(", ")}`);
|
|
142
|
+
}
|
|
143
|
+
if (data.telephone) lines.push(`**T\xE9l\xE9phone:** ${data.telephone}`);
|
|
144
|
+
if (data.email) lines.push(`**Email:** ${data.email}`);
|
|
145
|
+
if (data.lien_linkedin) lines.push(`**LinkedIn:** ${data.lien_linkedin}`);
|
|
146
|
+
if (data.numero_tva_intracommunautaire) {
|
|
147
|
+
lines.push(`**N\xB0 TVA:** ${data.numero_tva_intracommunautaire}`);
|
|
148
|
+
}
|
|
149
|
+
if (data.greffe) lines.push(`**Greffe:** ${data.greffe}`);
|
|
150
|
+
if (data.statut_rcs) lines.push(`**Statut RCS:** ${data.statut_rcs}`);
|
|
151
|
+
return textResult(lines.join("\n"));
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
server.tool(
|
|
155
|
+
"get-dirigeants",
|
|
156
|
+
"Get the list of directors/officers of a French company by SIREN number.",
|
|
157
|
+
{
|
|
158
|
+
siren: z.string().describe("SIREN number (9 digits)")
|
|
159
|
+
},
|
|
160
|
+
async (params) => {
|
|
161
|
+
const data = await pappers("/entreprise", {
|
|
162
|
+
siren: params.siren,
|
|
163
|
+
champs_supplementaires: "lien_linkedin"
|
|
164
|
+
});
|
|
165
|
+
if (!data.representants?.length) {
|
|
166
|
+
return textResult(`Aucun dirigeant trouv\xE9 pour ${data.nom_entreprise} (${data.siren}).`);
|
|
167
|
+
}
|
|
168
|
+
const lines = [`# Dirigeants de ${data.nom_entreprise} (${data.siren})
|
|
169
|
+
`];
|
|
170
|
+
for (const d of data.representants) {
|
|
171
|
+
if (d.personne_morale && d.denomination) {
|
|
172
|
+
const parts = [`### ${d.denomination}`];
|
|
173
|
+
if (d.siren) parts.push(`SIREN: ${d.siren}`);
|
|
174
|
+
if (d.qualite) parts.push(`Fonction: ${d.qualite}`);
|
|
175
|
+
lines.push(parts.join("\n"));
|
|
176
|
+
} else {
|
|
177
|
+
const name = d.nom_complet || `${d.prenom || ""} ${d.nom || ""}`.trim();
|
|
178
|
+
const parts = [`### ${name}`];
|
|
179
|
+
if (d.qualite) parts.push(`Fonction: ${d.qualite}`);
|
|
180
|
+
if (d.date_de_naissance_formate) parts.push(`Date de naissance: ${d.date_de_naissance_formate}`);
|
|
181
|
+
if (d.nationalite) parts.push(`Nationalit\xE9: ${d.nationalite}`);
|
|
182
|
+
lines.push(parts.join("\n"));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (data.lien_linkedin) lines.push(`
|
|
186
|
+
**LinkedIn entreprise:** ${data.lien_linkedin}`);
|
|
187
|
+
return textResult(lines.join("\n\n"));
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
server.tool(
|
|
191
|
+
"get-finances",
|
|
192
|
+
"Get financial data (revenue, profit, workforce) of a French company by SIREN number.",
|
|
193
|
+
{
|
|
194
|
+
siren: z.string().describe("SIREN number (9 digits)")
|
|
195
|
+
},
|
|
196
|
+
async (params) => {
|
|
197
|
+
const data = await pappers("/entreprise", {
|
|
198
|
+
siren: params.siren,
|
|
199
|
+
champs_supplementaires: "finances"
|
|
200
|
+
});
|
|
201
|
+
if (!data.finances?.length) {
|
|
202
|
+
return textResult(
|
|
203
|
+
`Aucune donnee financiere trouvee pour ${data.nom_entreprise} (${data.siren}).`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const lines = [`# Donnees financieres de ${data.nom_entreprise} (${data.siren})
|
|
207
|
+
`];
|
|
208
|
+
for (const f of data.finances) {
|
|
209
|
+
const year = f.annee || f.date_cloture_formate || f.date_cloture || "N/A";
|
|
210
|
+
const parts = [`### Exercice ${year}`];
|
|
211
|
+
if (f.date_cloture_formate) parts.push(`Cloture: ${f.date_cloture_formate}`);
|
|
212
|
+
if (f.duree_exercice) parts.push(`Duree: ${f.duree_exercice} mois`);
|
|
213
|
+
if (f.chiffre_affaires != null) {
|
|
214
|
+
parts.push(`Chiffre d'affaires: ${formatCurrency(f.chiffre_affaires)}`);
|
|
215
|
+
}
|
|
216
|
+
if (f.resultat != null) parts.push(`Resultat: ${formatCurrency(f.resultat)}`);
|
|
217
|
+
if (f.resultat_net != null) parts.push(`Resultat net: ${formatCurrency(f.resultat_net)}`);
|
|
218
|
+
if (f.resultat_exploitation != null) {
|
|
219
|
+
parts.push(`Resultat d'exploitation: ${formatCurrency(f.resultat_exploitation)}`);
|
|
220
|
+
}
|
|
221
|
+
if (f.excedent_brut_exploitation != null) {
|
|
222
|
+
parts.push(`EBE: ${formatCurrency(f.excedent_brut_exploitation)}`);
|
|
223
|
+
}
|
|
224
|
+
if (f.marge_brute != null) parts.push(`Marge brute: ${formatCurrency(f.marge_brute)}`);
|
|
225
|
+
if (f.effectif != null) parts.push(`Effectif: ${f.effectif}`);
|
|
226
|
+
if (f.capitaux_propres != null) {
|
|
227
|
+
parts.push(`Capitaux propres: ${formatCurrency(f.capitaux_propres)}`);
|
|
228
|
+
}
|
|
229
|
+
if (f.total_bilan != null) parts.push(`Total bilan: ${formatCurrency(f.total_bilan)}`);
|
|
230
|
+
lines.push(parts.join("\n"));
|
|
231
|
+
}
|
|
232
|
+
return textResult(lines.join("\n\n"));
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
server.tool(
|
|
236
|
+
"search-dirigeant",
|
|
237
|
+
"Search for company directors/officers by name.",
|
|
238
|
+
{
|
|
239
|
+
q: z.string().describe("Director name to search for"),
|
|
240
|
+
page: z.string().default("1").describe("Page number (default 1)"),
|
|
241
|
+
par_page: z.string().default("10").describe("Results per page (default 10)")
|
|
242
|
+
},
|
|
243
|
+
async (params) => {
|
|
244
|
+
const data = await pappers("/recherche-dirigeants", {
|
|
245
|
+
q: params.q,
|
|
246
|
+
page: params.page,
|
|
247
|
+
par_page: params.par_page
|
|
248
|
+
});
|
|
249
|
+
if (!data.resultats?.length) {
|
|
250
|
+
return textResult("Aucun dirigeant trouve.");
|
|
251
|
+
}
|
|
252
|
+
const lines = [`**${data.total} resultats** (page ${data.page})
|
|
253
|
+
`];
|
|
254
|
+
for (const d of data.resultats) {
|
|
255
|
+
const name = `${d.prenom || ""} ${d.nom || ""}`.trim();
|
|
256
|
+
const parts = [`### ${name}`];
|
|
257
|
+
if (d.date_de_naissance_formate || d.date_de_naissance) {
|
|
258
|
+
parts.push(
|
|
259
|
+
`Date de naissance: ${d.date_de_naissance_formate || d.date_de_naissance}`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
if (d.nationalite) parts.push(`Nationalite: ${d.nationalite}`);
|
|
263
|
+
if (d.entreprises?.length) {
|
|
264
|
+
parts.push("Entreprises:");
|
|
265
|
+
for (const e of d.entreprises) {
|
|
266
|
+
parts.push(`- ${e.nom_entreprise || "N/A"} (SIREN: ${e.siren || "N/A"}) \u2014 ${e.qualite || "N/A"}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
lines.push(parts.join("\n"));
|
|
270
|
+
}
|
|
271
|
+
return textResult(lines.join("\n\n"));
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
function formatCurrency(value) {
|
|
275
|
+
return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", maximumFractionDigits: 0 }).format(value);
|
|
276
|
+
}
|
|
277
|
+
async function main() {
|
|
278
|
+
const transport = new StdioServerTransport();
|
|
279
|
+
await server.connect(transport);
|
|
280
|
+
}
|
|
281
|
+
main().catch((err) => {
|
|
282
|
+
console.error("Fatal error:", err);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mnicole-dev/pappers-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for the Pappers API (French company information)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pappers-mcp-server": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format esm --out-dir dist --clean",
|
|
15
|
+
"dev": "tsx src/index.ts",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/mnicole90/pappers-mcp-server.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/mnicole90/pappers-mcp-server#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/mnicole90/pappers-mcp-server/issues"
|
|
25
|
+
},
|
|
26
|
+
"author": "Maxime Nicole <maxime@kodesaas.com> (https://kodesaas.com)",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"pappers",
|
|
33
|
+
"entreprise",
|
|
34
|
+
"siren",
|
|
35
|
+
"siret",
|
|
36
|
+
"french-companies",
|
|
37
|
+
"model-context-protocol"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
42
|
+
"zod": "^4.3.6"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"tsup": "^8.4.0",
|
|
46
|
+
"tsx": "^4.19.0",
|
|
47
|
+
"typescript": "^5.8.0"
|
|
48
|
+
}
|
|
49
|
+
}
|