|
2 | 2 |
|
3 | 3 | `Skills` is an opt-in [`ClientExtension`](../advanced/extensions.md) for talking |
4 | 4 | to a skills catalog server. Register it with `Client(extensions=[Skills()])`, |
5 | | -then call `bind(client)` for the SEP-2640 verbs — `list_skills`, `get_skill`, |
| 5 | +then call `client.extension(Skills)` for the SEP-2640 verbs — `list_skills`, `get_skill`, |
6 | 6 | `read_skill_uri`, and `read_directory` — tied to that connection: |
7 | 7 |
|
8 | | - async with Client("http://localhost:8000/mcp", extensions=[skills := Skills()]) as client: |
9 | | - for skill in await skills.bind(client).list_skills(): |
| 8 | + async with Client("http://localhost:8000/mcp", extensions=[Skills()]) as client: |
| 9 | + for skill in await client.extension(Skills).list_skills(): |
10 | 10 | print(skill.uri, skill.frontmatter["description"]) |
11 | 11 |
|
12 | | -`bind(client)` returns a `BoundSkills`. Its catalog verbs — `list_skills`, |
| 12 | +`client.extension(Skills)` returns a `BoundSkills`. Its catalog verbs — `list_skills`, |
13 | 13 | `get_skill`, and `read_directory` — check that the server advertises the |
14 | 14 | extension and validate its response; `list_skills` and `read_directory` follow |
15 | 15 | `nextCursor` to completion, so one call returns every page's results. |
|
19 | 19 |
|
20 | 20 | from __future__ import annotations |
21 | 21 |
|
22 | | -from typing import TYPE_CHECKING |
23 | | - |
24 | 22 | from mcp_types import ReadResourceResult, Resource |
25 | 23 |
|
26 | 24 | from mcp.client.extension import ClientExtension |
|
41 | 39 | ) |
42 | 40 | from mcp.shared.skills import verify_skill_resource as verify_skill_resource |
43 | 41 |
|
44 | | -if TYPE_CHECKING: |
45 | | - from mcp.client.client import Client |
46 | | - |
47 | 42 | __all__ = ["BoundSkills", "Skills", "verify_skill_resource"] |
48 | 43 |
|
49 | 44 |
|
50 | 45 | class Skills(ClientExtension): |
51 | | - """The client-side Skills extension: register, then `bind` for typed verbs. |
| 46 | + """The client-side Skills extension: register, then access its typed verbs. |
52 | 47 |
|
53 | 48 | Pass an instance to `Client(extensions=[Skills()])` — this advertises |
54 | 49 | `io.modelcontextprotocol/skills` under the client's capabilities — and call |
55 | | - `bind(client)` once the client is connected for a `BoundSkills` handle. |
| 50 | + `client.extension(Skills)` once connected for a `BoundSkills` handle. |
56 | 51 | """ |
57 | 52 |
|
58 | 53 | identifier = EXTENSION_ID |
59 | 54 |
|
60 | | - def bind(self, client: Client) -> BoundSkills: |
61 | | - """Return the SEP-2640 verbs bound to `client`'s connected session. |
62 | | -
|
63 | | - Raises: |
64 | | - RuntimeError: If `client` has not entered its `async with` block yet. |
65 | | - """ |
66 | | - return BoundSkills(client.session) |
| 55 | + def bind(self, session: ClientSession) -> BoundSkills: |
| 56 | + """Return the SEP-2640 verbs bound to `session`.""" |
| 57 | + return BoundSkills(session) |
67 | 58 |
|
68 | 59 |
|
69 | 60 | class BoundSkills: |
70 | 61 | """The SEP-2640 verbs bound to one connected session. |
71 | 62 |
|
72 | | - Obtain it from `Skills.bind(client)`. The catalog verbs — `list_skills`, |
| 63 | + Obtain it from `client.extension(Skills)`. The catalog verbs — `list_skills`, |
73 | 64 | `get_skill`, and `read_directory` — check that the server advertises the |
74 | 65 | extension and validate its response against the SEP-2640 conformance rules |
75 | 66 | before returning; `list_skills` and `read_directory` also follow |
|
0 commit comments