salesforce-agent 2.3.2__tar.gz → 2.3.4__tar.gz

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.
Files changed (73) hide show
  1. {salesforce_agent-2.3.2/salesforce_agent.egg-info → salesforce_agent-2.3.4}/PKG-INFO +4 -8
  2. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/README.md +0 -2
  3. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/pyproject.toml +12 -17
  4. salesforce_agent-2.3.4/salesforce_agent/__init__.py +19 -0
  5. salesforce_agent-2.3.4/salesforce_agent/__main__.py +4 -0
  6. salesforce_agent-2.3.4/salesforce_agent/connector_sources.py +103 -0
  7. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/kg_ingest.py +3 -60
  8. salesforce_agent-2.3.4/salesforce_agent/mcp_server.py +49 -0
  9. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/certification.json +6 -9
  10. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/mappings/source.yaml +1 -1
  11. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/salesforce.ttl +3 -5
  12. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/prompts/crm_specialist.json +0 -2
  13. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4/salesforce_agent.egg-info}/PKG-INFO +4 -8
  14. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/SOURCES.txt +1 -9
  15. salesforce_agent-2.3.4/salesforce_agent.egg-info/entry_points.txt +8 -0
  16. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/requires.txt +2 -5
  17. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_fleet_name.py +3 -14
  18. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_kg_ingest.py +8 -8
  19. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_startup.py +2 -11
  20. salesforce_agent-2.3.2/MANIFEST.in +0 -4
  21. salesforce_agent-2.3.2/requirements.txt +0 -2
  22. salesforce_agent-2.3.2/salesforce_agent/__init__.py +0 -65
  23. salesforce_agent-2.3.2/salesforce_agent/__main__.py +0 -4
  24. salesforce_agent-2.3.2/salesforce_agent/connectors/__init__.py +0 -0
  25. salesforce_agent-2.3.2/salesforce_agent/connectors/mcp_source_presets.json +0 -29
  26. salesforce_agent-2.3.2/salesforce_agent/connectors/tool_schema_fingerprints.json +0 -8
  27. salesforce_agent-2.3.2/salesforce_agent/mcp_server.py +0 -99
  28. salesforce_agent-2.3.2/salesforce_agent/prompts/__init__.py +0 -0
  29. salesforce_agent-2.3.2/salesforce_agent/skills/__init__.py +0 -0
  30. salesforce_agent-2.3.2/salesforce_agent.egg-info/entry_points.txt +0 -17
  31. salesforce_agent-2.3.2/tests/test_default_content_surfaces.py +0 -43
  32. salesforce_agent-2.3.2/tests/test_init_dynamics.py +0 -12
  33. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/LICENSE +0 -0
  34. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/__init__.py +0 -0
  35. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_admin.py +0 -0
  36. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_base.py +0 -0
  37. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_bulk.py +0 -0
  38. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_describe.py +0 -0
  39. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_query.py +0 -0
  40. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_records.py +0 -0
  41. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api_client.py +0 -0
  42. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/auth.py +0 -0
  43. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp/__init__.py +0 -0
  44. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp/mcp_salesforce.py +0 -0
  45. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp_config.json +0 -0
  46. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/__init__.py +0 -0
  47. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/fixtures/records.json +0 -0
  48. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/migrations/manifest.json +0 -0
  49. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/shapes/connector.shacl.ttl +0 -0
  50. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_input_models.py +0 -0
  51. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_response_models.py +0 -0
  52. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/SKILL.md +0 -0
  53. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/agents/openai.yaml +0 -0
  54. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/references/catalog.md +0 -0
  55. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-crm-knowledge-graph/SKILL.md +0 -0
  56. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-crm-knowledge-graph/WORKFLOW.md +0 -0
  57. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-record-management/SKILL.md +0 -0
  58. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-record-management/WORKFLOW.md +0 -0
  59. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-soql-query/SKILL.md +0 -0
  60. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-soql-query/WORKFLOW.md +0 -0
  61. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/dependency_links.txt +0 -0
  62. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/top_level.txt +0 -0
  63. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/setup.cfg +0 -0
  64. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_admin.py +0 -0
  65. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_api_wrapper.py +0 -0
  66. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_auth.py +0 -0
  67. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_bulk.py +0 -0
  68. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_describe.py +0 -0
  69. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_errors.py +0 -0
  70. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_query.py +0 -0
  71. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_records.py +0 -0
  72. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_salesforce_mcp_validation.py +0 -0
  73. {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_salesforce_models.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: salesforce-agent
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!
5
- Author-email: Project Maintainers <maintainers@users.noreply.github.com>
5
+ Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
7
7
  Classifier: Development Status :: 4 - Beta
8
8
  Classifier: License :: OSI Approved :: MIT License
@@ -12,14 +12,12 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: <3.15,>=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18
15
+ Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
16
16
  Requires-Dist: httpx>=0.28.1
17
- Provides-Extra: mcp
18
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
19
17
  Provides-Extra: jwt
20
18
  Requires-Dist: cryptography>=50.0.2; extra == "jwt"
21
19
  Provides-Extra: all
22
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "all"
20
+ Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
23
21
  Requires-Dist: cryptography>=50.0.2; extra == "all"
24
22
  Provides-Extra: test
25
23
  Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
@@ -40,8 +38,6 @@ Dynamic: license-file
40
38
  ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/salesforce-agent)
41
39
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/salesforce-agent)
42
40
 
43
- *Version: 2.3.2*
44
-
45
41
  > **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
46
42
  > server live on the docs site:
47
43
  > <https://knuckles-team.github.io/salesforce-agent/>
@@ -9,8 +9,6 @@
9
9
  ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/salesforce-agent)
10
10
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/salesforce-agent)
11
11
 
12
- *Version: 2.3.2*
13
-
14
12
  > **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
15
13
  > server live on the docs site:
16
14
  > <https://knuckles-team.github.io/salesforce-agent/>
@@ -4,43 +4,33 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "salesforce-agent"
7
- version = "2.3.2"
7
+ version = "2.3.4"
8
8
  description = "Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!"
9
9
  readme = "README.md"
10
10
  classifiers = [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
11
11
  requires-python = ">=3.12, <3.15"
12
- dependencies = [ "agent-connector-sdk[mcp]>=0.3.18,<1.0.0", "httpx>=0.28.1",]
12
+ dependencies = [ "agent-connector-sdk[mcp]>=0.5.4,<0.6.0", "httpx>=0.28.1",]
13
13
  [[project.authors]]
14
- name = "Project Maintainers"
15
- email = "maintainers@users.noreply.github.com"
14
+ name = "Repository Maintainers"
15
+ email = "maintainers@knuckles.team"
16
16
 
17
17
  [project.license]
18
18
  text = "MIT"
19
19
 
20
20
  [project.optional-dependencies]
21
- mcp = [ "agent-connector-sdk[mcp]>=0.3.18,<1.0.0",]
22
21
  jwt = [ "cryptography>=50.0.2",]
23
- all = [ "agent-connector-sdk[mcp]>=0.3.18,<1.0.0", "cryptography>=50.0.2",]
22
+ all = [ "agent-connector-sdk[mcp]>=0.4.1,<1.0.0", "cryptography>=50.0.2",]
24
23
  test = [ "pytest-xdist>=3.8.0", "pytest>=9.1.1", "pytest-asyncio>=1.4.0", "pytest-cov>=7.1.0", "cryptography>=50.0.2",]
25
24
 
26
25
  [project.scripts]
27
- salesforce-mcp = "salesforce_agent.mcp_server:mcp_server"
28
-
29
- [project.entry-points."agent_connector_sdk.skill_providers"]
30
- salesforce-agent = "salesforce_agent.skills"
31
-
32
- [project.entry-points."agent_connector_sdk.ontology_providers"]
33
- salesforce-agent = "salesforce_agent.ontology"
34
-
35
- [project.entry-points."agent_connector_sdk.source_connector_providers"]
36
- salesforce-agent = "salesforce_agent.connectors"
26
+ salesforce-mcp = "agent_connector_sdk.cli:serve"
37
27
 
38
28
  [project.entry-points."agent_connector_sdk.prompt_providers"]
39
29
  salesforce-agent = "salesforce_agent.prompts"
40
30
 
41
31
  # The one declared connector identity: the fleet name (SDK-CONNECTOR-CONTROL-R071).
42
32
  [project.entry-points."agent_connector_sdk.connector"]
43
- salesforce-mcp = "salesforce_agent"
33
+ salesforce-mcp = "salesforce_agent:connector"
44
34
 
45
35
  [tool.uv.workspace]
46
36
  members = ["."]
@@ -54,6 +44,7 @@ override-dependencies = [
54
44
  ]
55
45
 
56
46
  [tool.ruff]
47
+ extend-exclude = ["tests", "scripts"]
57
48
  line-length = 88
58
49
  target-version = "py312"
59
50
 
@@ -81,3 +72,7 @@ ignore_names = ["request", "config", "exc_info"]
81
72
 
82
73
  [tool.pipelines_hooks.ste]
83
74
  exempt = ["specs/*", "specs/**/*"]
75
+
76
+ [tool.pipelines.container]
77
+ debug_apt = ["default-jre", "ripgrep", "tree", "fd-find", "curl", "nano", "build-essential", "cmake", "libssl-dev", "libcurl4-openssl-dev", "pkg-config", "cargo", "rustc"]
78
+ limits = {"mcp" = {"memory_limit_env" = "AGENT_CONTAINER_MEMORY_LIMIT", "memory_limit" = "4g", "cpu_limit_env" = "AGENT_CONTAINER_CPU_LIMIT", "cpu_limit" = "2.0"}}
@@ -0,0 +1,19 @@
1
+ """CONCEPT:AU-ECO.messaging.native-backend-abstraction Unified ecosystem initialization dynamic check."""
2
+
3
+ from agent_connector_sdk.connector import Connector
4
+
5
+ from salesforce_agent.api_client import Api
6
+ from salesforce_agent.auth import SalesforceAuth, SalesforceConfig, get_client
7
+ from salesforce_agent.mcp_server import _operation_targets
8
+
9
+ __all__ = ["Api", "SalesforceAuth", "SalesforceConfig", "connector", "get_client"]
10
+
11
+ connector = Connector(
12
+ tools="salesforce_agent.mcp_server",
13
+ instructions="Salesforce MCP Server — SOQL/SOSL queries, record CRUD with composite/collections batching, metadata describe, Bulk API 2.0 ingest, and org administration. Destructive operations are gated by SALESFORCE_ALLOW_DESTRUCTIVE.",
14
+ transports=(
15
+ "stdio",
16
+ "streamable-http",
17
+ ),
18
+ verbose_targets=tuple(_operation_targets()),
19
+ )
@@ -0,0 +1,4 @@
1
+ from agent_connector_sdk import run
2
+
3
+ if __name__ == "__main__":
4
+ run()
@@ -0,0 +1,103 @@
1
+ """Data sources of this connector, declared by tool name (generated by connector-ontology-map migrate).
2
+
3
+ Served live as ``connector://resources``. Regenerate by editing the declarations, not the tools.
4
+ """
5
+
6
+ # ruff: noqa: E501
7
+ from __future__ import annotations
8
+
9
+ from agent_connector_sdk.ingest.live_declaration import source_meta
10
+
11
+ SOURCES = (
12
+ source_meta(
13
+ tool="salesforce_soql_query",
14
+ source_id="salesforce-opportunities",
15
+ record_type="salesforce_opportunity",
16
+ id_field="Id",
17
+ preset={
18
+ "doc_type": "salesforce_opportunity",
19
+ "params": {
20
+ "soql": "SELECT Id, Name, StageName, Amount, CloseDate, Description FROM Opportunity",
21
+ },
22
+ "params_style": "args",
23
+ },
24
+ records_path="records",
25
+ server="salesforce-mcp",
26
+ text_field="Description",
27
+ title_field="Name",
28
+ ),
29
+ )
30
+
31
+ SCHEMA_VERSION = 2
32
+
33
+ FIELD_SETS = {
34
+ "fields_1": {
35
+ "amount": "xsd:decimal",
36
+ "closeDate": "xsd:date",
37
+ "email": "xsd:string",
38
+ "industry": "xsd:string",
39
+ "leadStatus": "xsd:string",
40
+ "salesforceId": "xsd:string",
41
+ "stageName": "xsd:string",
42
+ },
43
+ }
44
+
45
+ SCHEMA_MAPPINGS = {
46
+ "Account": {
47
+ "field_sets": ["fields_1"],
48
+ "ontology_class": None,
49
+ },
50
+ "Campaign": {
51
+ "field_sets": ["fields_1"],
52
+ "ontology_class": None,
53
+ },
54
+ "Case": {
55
+ "field_sets": ["fields_1"],
56
+ "ontology_class": None,
57
+ },
58
+ "Contact": {
59
+ "field_sets": ["fields_1"],
60
+ "ontology_class": "Person",
61
+ },
62
+ "Lead": {
63
+ "field_sets": ["fields_1"],
64
+ "ontology_class": None,
65
+ },
66
+ "Opportunity": {
67
+ "field_sets": ["fields_1"],
68
+ "ontology_class": None,
69
+ },
70
+ }
71
+
72
+ RESOURCES = (
73
+ {
74
+ "id_prefix": "account",
75
+ "label": "Account",
76
+ "name": "Account",
77
+ },
78
+ {
79
+ "id_prefix": "campaign",
80
+ "label": "Campaign",
81
+ "name": "Campaign",
82
+ },
83
+ {
84
+ "id_prefix": "case",
85
+ "label": "Case",
86
+ "name": "Case",
87
+ },
88
+ {
89
+ "id_prefix": "contact",
90
+ "label": "Contact",
91
+ "name": "Contact",
92
+ },
93
+ {
94
+ "id_prefix": "lead",
95
+ "label": "Lead",
96
+ "name": "Lead",
97
+ },
98
+ {
99
+ "id_prefix": "opportunity",
100
+ "label": "Opportunity",
101
+ "name": "Opportunity",
102
+ },
103
+ )
@@ -14,71 +14,14 @@ import logging
14
14
  from typing import Any
15
15
 
16
16
  from agent_connector_sdk.ingest import (
17
- ChangeSet,
18
- Entity,
19
- IngestBinding,
20
17
  IngestError,
21
18
  KnowledgeIngest,
22
- Relationship,
23
- current_ingest,
19
+ SourceStream,
24
20
  )
25
21
 
26
22
  logger = logging.getLogger("salesforce_agent.kg")
27
23
 
28
- _BINDING = IngestBinding(connector="salesforce-mcp", stream="salesforce")
29
-
30
- _ENTITY_RESERVED_KEYS = frozenset({"id", "node_type"})
31
- _RELATIONSHIP_RESERVED_KEYS = frozenset({"source", "target", "relationship"})
32
-
33
-
34
- def _to_entity(record: dict[str, Any]) -> Entity:
35
- return Entity(
36
- id=record.get("id"),
37
- node_type=record.get("node_type"),
38
- properties={
39
- key: value
40
- for key, value in record.items()
41
- if key not in _ENTITY_RESERVED_KEYS
42
- },
43
- )
44
-
45
-
46
- def _to_relationship(record: dict[str, Any]) -> Relationship:
47
- properties = {
48
- key: value
49
- for key, value in record.items()
50
- if key not in _RELATIONSHIP_RESERVED_KEYS
51
- }
52
- return Relationship(
53
- source=record["source"],
54
- target=record["target"],
55
- relationship=record["relationship"],
56
- properties=properties or None,
57
- )
58
-
59
-
60
- async def ingest_entities(
61
- entities: list[dict[str, Any]],
62
- relationships: list[dict[str, Any]] | None = None,
63
- *,
64
- ingest: KnowledgeIngest | None = None,
65
- ) -> dict[str, int]:
66
- """Write canonical typed nodes and relationships via the SDK ingest facade.
67
-
68
- Uses canonical ``node_type`` / ``relationship`` structural fields and surfaces
69
- a malformed change set or a refused commit as ``IngestError``.
70
- """
71
- if not entities:
72
- raise IngestError("ingest_entities needs at least one entity")
73
- change_set = ChangeSet(
74
- entities=tuple(_to_entity(entity) for entity in entities),
75
- relationships=tuple(
76
- _to_relationship(relationship) for relationship in relationships or ()
77
- ),
78
- )
79
- service = ingest or current_ingest()
80
- receipt = await service.submit(_BINDING, change_set)
81
- return {"nodes": receipt.affected_count, "edges": receipt.relationship_count}
24
+ STREAM = SourceStream.for_package(__package__.split(".")[0], "salesforce")
82
25
 
83
26
 
84
27
  # --------------------------------------------------------------------------- #
@@ -283,4 +226,4 @@ async def ingest_records(
283
226
  if mapper is None:
284
227
  raise IngestError(f"unsupported Salesforce object: {sobject!r}")
285
228
  entities, relationships = mapper(records)
286
- return await ingest_entities(entities, relationships, ingest=ingest)
229
+ return await STREAM.entities(entities, relationships, ingest=ingest)
@@ -0,0 +1,49 @@
1
+ """Main FastMCP server and tool registration for the Salesforce connector."""
2
+
3
+ from typing import Any
4
+
5
+ from salesforce_agent.api import (
6
+ AdminClient,
7
+ BulkClient,
8
+ DescribeClient,
9
+ QueryClient,
10
+ RecordsClient,
11
+ )
12
+ from salesforce_agent.auth import get_client
13
+ from salesforce_agent.mcp.mcp_salesforce import (
14
+ register_admin_tools,
15
+ register_bulk_tools,
16
+ register_describe_tools,
17
+ register_ingest_tools,
18
+ register_records_tools,
19
+ register_soql_tools,
20
+ )
21
+
22
+ # SDK discovery registers the register_<tag>_tools functions bound in this module.
23
+ __all__ = [
24
+ "register_admin_tools",
25
+ "register_bulk_tools",
26
+ "register_describe_tools",
27
+ "register_ingest_tools",
28
+ "register_records_tools",
29
+ "register_soql_tools",
30
+ ]
31
+
32
+
33
+ def _operation_targets() -> list[dict[str, Any]]:
34
+ """One operation-tool group per resource client of the ``Api`` facade."""
35
+ resources = {
36
+ "soql": QueryClient,
37
+ "records": RecordsClient,
38
+ "describe": DescribeClient,
39
+ "bulk": BulkClient,
40
+ "admin": AdminClient,
41
+ }
42
+ return [
43
+ {
44
+ "client_cls": client_cls,
45
+ "get_client": (lambda name=name: getattr(get_client(), name)),
46
+ "prefix": f"salesforce_{name}",
47
+ }
48
+ for name, client_cls in resources.items()
49
+ ]
@@ -1,13 +1,10 @@
1
1
  {
2
- "api_version": "arbora.io/v1",
2
+ "api_version": "graphos.io/v1",
3
3
  "artifacts": {
4
- "connector_manifest.yml": "8f242e7c62b075786c8c47967e40d62aa44a967593782ae679771dc27e4693e8",
5
- "salesforce_agent/connectors/mcp_source_presets.json": "644ed7237882e5b5ac96b1c16696e1348a15f025c0d10c23745dfcd8ea6d0c87",
6
- "salesforce_agent/connectors/tool_schema_fingerprints.json": "f2db55d366dd1f4b9da00ac78433cbc0a627109d15a23d3a5bdda3d493e1c8f3",
7
4
  "salesforce_agent/ontology/fixtures/records.json": "b344913dc0bbc8999151a56c1802f1c15cf818888a0ab8aaa5063326b21e9043",
8
- "salesforce_agent/ontology/mappings/source.yaml": "a138feb24291bd26939a85e7e786dc158d145a7be056ae6cc3b69e8342fdaa3c",
5
+ "salesforce_agent/ontology/mappings/source.yaml": "5292026d92f27af428a32e62d8ece64aa25ee3ef81212f11d960bfb0da614af1",
9
6
  "salesforce_agent/ontology/migrations/manifest.json": "76e71d3e6fbb573e65cb9ce25868523b5aa8ba1f4cca15b266d343ee9d2b42fc",
10
- "salesforce_agent/ontology/salesforce.ttl": "ecf135e009a2cd6cd0029952728311c7b1d0e86fda8cfbd9bb49f50c98587bf2",
7
+ "salesforce_agent/ontology/salesforce.ttl": "fd5b77e12fd1db5ba65d45bba24657e70aa8e60682b51a234d93f2b762ef45c1",
11
8
  "salesforce_agent/ontology/shapes/connector.shacl.ttl": "643358fd71781e6efc38edfac45ad28cf895741e5d29836e9542d33eda7193f4"
12
9
  },
13
10
  "checks": {
@@ -18,11 +15,11 @@
18
15
  "synthetic_fixture_contract": "passed"
19
16
  },
20
17
  "compatibility": {
21
- "agent_connector_sdk": ">=2.5.0,<3",
18
+ "agent_utilities": ">=2.5.0,<3",
22
19
  "bundle_schema": "2",
23
20
  "epistemic_graph": ">=2.27.0,<3"
24
21
  },
25
- "connector": "salesforce-mcp",
22
+ "connector": "salesforce-agent",
26
23
  "kind": "ConnectorSourceAttestation",
27
24
  "live_certified": false,
28
25
  "mode": "offline-source",
@@ -32,5 +29,5 @@
32
29
  "signer": "UNSIGNED-PREVIEW",
33
30
  "signing_public_key": "",
34
31
  "status": "source-validated",
35
- "validated_at": "2026-08-26T13:42:55Z"
32
+ "validated_at": "2026-10-24T12:23:32Z"
36
33
  }
@@ -1,5 +1,5 @@
1
1
  schema_version: '1'
2
- connector: salesforce-agent
2
+ connector: salesforce-mcp
3
3
  ontology_source: salesforce
4
4
  sync:
5
5
  - preset: salesforce-accounts
@@ -13,9 +13,8 @@
13
13
  # (salesforce_soql / salesforce_records / salesforce_describe / salesforce_ingest_crm).
14
14
  # :Person (shared) is REUSED for the owning Salesforce User — never redefined here.
15
15
 
16
- :Account a owl:Class ;
17
- rdfs:label "Account" ;
18
- rdfs:comment "A company or organization tracked in Salesforce CRM (sObject Account)." .
16
+ :Account a owl:Class .
17
+
19
18
 
20
19
  :Contact a owl:Class ;
21
20
  rdfs:label "Contact" ;
@@ -131,5 +130,4 @@
131
130
  rdfs:comment """Salesforce CRM model — accounts, contacts, opportunities, leads,
132
131
  cases and campaigns with their sales and service relationships — federated into
133
132
  the agent-connector-sdk knowledge-graph hub. Reuses the shared :Person for the owning
134
- Salesforce User.""" ;
135
- owl:imports <http://knuckles.team/kg/enterprise> .
133
+ Salesforce User.""" .
@@ -4,8 +4,6 @@
4
4
  "schema_version": "1.0",
5
5
  "prompt_version": "0.1.0",
6
6
  "source": "salesforce-agent",
7
- "extends": "agent-connector-sdk:base",
8
- "compose": "append",
9
7
  "description": "Salesforce CRM specialist: SOQL/SOSL analysis, safe record management, and knowledge-graph ingestion over the salesforce-agent MCP server.",
10
8
  "metadata": {
11
9
  "topic": "Salesforce CRM",
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: salesforce-agent
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!
5
- Author-email: Project Maintainers <maintainers@users.noreply.github.com>
5
+ Author-email: Repository Maintainers <maintainers@knuckles.team>
6
6
  License: MIT
7
7
  Classifier: Development Status :: 4 - Beta
8
8
  Classifier: License :: OSI Approved :: MIT License
@@ -12,14 +12,12 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: <3.15,>=3.12
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18
15
+ Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
16
16
  Requires-Dist: httpx>=0.28.1
17
- Provides-Extra: mcp
18
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
19
17
  Provides-Extra: jwt
20
18
  Requires-Dist: cryptography>=50.0.2; extra == "jwt"
21
19
  Provides-Extra: all
22
- Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "all"
20
+ Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
23
21
  Requires-Dist: cryptography>=50.0.2; extra == "all"
24
22
  Provides-Extra: test
25
23
  Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
@@ -40,8 +38,6 @@ Dynamic: license-file
40
38
  ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/salesforce-agent)
41
39
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/salesforce-agent)
42
40
 
43
- *Version: 2.3.2*
44
-
45
41
  > **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
46
42
  > server live on the docs site:
47
43
  > <https://knuckles-team.github.io/salesforce-agent/>
@@ -1,12 +1,11 @@
1
1
  LICENSE
2
- MANIFEST.in
3
2
  README.md
4
3
  pyproject.toml
5
- requirements.txt
6
4
  salesforce_agent/__init__.py
7
5
  salesforce_agent/__main__.py
8
6
  salesforce_agent/api_client.py
9
7
  salesforce_agent/auth.py
8
+ salesforce_agent/connector_sources.py
10
9
  salesforce_agent/kg_ingest.py
11
10
  salesforce_agent/mcp_config.json
12
11
  salesforce_agent/mcp_server.py
@@ -25,9 +24,6 @@ salesforce_agent/api/api_client_bulk.py
25
24
  salesforce_agent/api/api_client_describe.py
26
25
  salesforce_agent/api/api_client_query.py
27
26
  salesforce_agent/api/api_client_records.py
28
- salesforce_agent/connectors/__init__.py
29
- salesforce_agent/connectors/mcp_source_presets.json
30
- salesforce_agent/connectors/tool_schema_fingerprints.json
31
27
  salesforce_agent/mcp/__init__.py
32
28
  salesforce_agent/mcp/mcp_salesforce.py
33
29
  salesforce_agent/ontology/__init__.py
@@ -37,9 +33,7 @@ salesforce_agent/ontology/fixtures/records.json
37
33
  salesforce_agent/ontology/mappings/source.yaml
38
34
  salesforce_agent/ontology/migrations/manifest.json
39
35
  salesforce_agent/ontology/shapes/connector.shacl.ttl
40
- salesforce_agent/prompts/__init__.py
41
36
  salesforce_agent/prompts/crm_specialist.json
42
- salesforce_agent/skills/__init__.py
43
37
  salesforce_agent/skills/salesforce-agent-operations/SKILL.md
44
38
  salesforce_agent/skills/salesforce-agent-operations/agents/openai.yaml
45
39
  salesforce_agent/skills/salesforce-agent-operations/references/catalog.md
@@ -53,11 +47,9 @@ tests/test_admin.py
53
47
  tests/test_api_wrapper.py
54
48
  tests/test_auth.py
55
49
  tests/test_bulk.py
56
- tests/test_default_content_surfaces.py
57
50
  tests/test_describe.py
58
51
  tests/test_errors.py
59
52
  tests/test_fleet_name.py
60
- tests/test_init_dynamics.py
61
53
  tests/test_kg_ingest.py
62
54
  tests/test_query.py
63
55
  tests/test_records.py
@@ -0,0 +1,8 @@
1
+ [agent_connector_sdk.connector]
2
+ salesforce-mcp = salesforce_agent:connector
3
+
4
+ [agent_connector_sdk.prompt_providers]
5
+ salesforce-agent = salesforce_agent.prompts
6
+
7
+ [console_scripts]
8
+ salesforce-mcp = agent_connector_sdk.cli:serve
@@ -1,16 +1,13 @@
1
- agent-connector-sdk[mcp]<1.0.0,>=0.3.18
1
+ agent-connector-sdk[mcp]<0.6.0,>=0.5.4
2
2
  httpx>=0.28.1
3
3
 
4
4
  [all]
5
- agent-connector-sdk[mcp]<1.0.0,>=0.3.18
5
+ agent-connector-sdk[mcp]<1.0.0,>=0.4.1
6
6
  cryptography>=50.0.2
7
7
 
8
8
  [jwt]
9
9
  cryptography>=50.0.2
10
10
 
11
- [mcp]
12
- agent-connector-sdk[mcp]<1.0.0,>=0.3.18
13
-
14
11
  [test]
15
12
  pytest-xdist>=3.8.0
16
13
  pytest>=9.1.1
@@ -2,9 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from agent_connector_sdk.connector_identity import connector_name
5
6
  import ast
6
- import json
7
- import re
8
7
  import tomllib
9
8
  from pathlib import Path
10
9
 
@@ -36,18 +35,8 @@ def _call_connectors(path: Path) -> list[str]:
36
35
  def test_connector_name_is_the_fleet_name() -> None:
37
36
  pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
38
37
  assert pyproject["project"]["entry-points"]["agent_connector_sdk.connector"] == {
39
- FLEET: "salesforce_agent"
38
+ FLEET: "salesforce_agent:connector"
40
39
  }
41
- manifest_path = PACKAGE / "connector_manifest.yml"
42
- if not manifest_path.is_file():
43
- manifest_path = ROOT / "connector_manifest.yml"
44
- manifest = manifest_path.read_text(encoding="utf-8")
45
- match = re.search(r'^\s*"?connector"?\s*:\s*"?([^"\s,]+)', manifest, re.MULTILINE)
46
- assert match is not None and match.group(1) == FLEET
47
- fingerprints = PACKAGE / "connectors" / "tool_schema_fingerprints.json"
48
- if fingerprints.is_file():
49
- assert (
50
- json.loads(fingerprints.read_text(encoding="utf-8"))["connector"] == FLEET
51
- )
40
+ assert connector_name("salesforce_agent") == FLEET
52
41
  for module in sorted(PACKAGE.glob("*.py")):
53
42
  assert all(name == FLEET for name in _call_connectors(module)), module.name
@@ -19,7 +19,7 @@ from epistemic_graph.generated.source_ingestion import SourceIngestionRequest
19
19
 
20
20
  from salesforce_agent.kg_ingest import (
21
21
  INGEST_QUERIES,
22
- ingest_entities,
22
+ STREAM,
23
23
  ingest_records,
24
24
  map_leads,
25
25
  )
@@ -54,7 +54,7 @@ def ingest() -> tuple[KnowledgeIngest, _FakeTransport]:
54
54
  @pytest.mark.asyncio
55
55
  async def test_ingest_entities_writes_nodes_and_edges(ingest):
56
56
  service, transport = ingest
57
- res = await ingest_entities(
57
+ res = await STREAM.entities(
58
58
  [
59
59
  {"id": "a", "node_type": "Account", "name": "Acme"},
60
60
  {"id": "b", "node_type": "Contact"},
@@ -70,7 +70,7 @@ async def test_ingest_entities_writes_nodes_and_edges(ingest):
70
70
  a_record = next(r for r in request.records if r.record_id == "a")
71
71
  assert a_record.payload["name"] == "Acme"
72
72
  assert request.relationships[0].relation_reference.endswith(
73
- "resources/Contact/relations/worksAtAccount"
73
+ "relations/Contact/worksAtAccount"
74
74
  )
75
75
 
76
76
 
@@ -94,7 +94,7 @@ async def test_ingest_records_accounts_with_owner(ingest):
94
94
  r.record_id == "salesforce:User:005U" for r in request.records
95
95
  )
96
96
  assert request.relationships[0].relation_reference.endswith(
97
- "resources/Account/relations/ownedBy"
97
+ "relations/Account/ownedBy"
98
98
  )
99
99
 
100
100
 
@@ -114,7 +114,7 @@ async def test_ingest_records_contact_links_account(ingest):
114
114
  # the SDK's persistence privacy guard redacts email-shaped values.
115
115
  assert contact.payload["email"] == "[REDACTED_EMAIL]"
116
116
  assert request.relationships[0].relation_reference.endswith(
117
- "resources/Contact/relations/worksAtAccount"
117
+ "relations/Contact/worksAtAccount"
118
118
  )
119
119
 
120
120
 
@@ -133,7 +133,7 @@ async def test_ingest_records_opportunity_links_account(ingest):
133
133
  )
134
134
  assert opp.payload["stageName"] == "Won"
135
135
  assert request.relationships[0].relation_reference.endswith(
136
- "resources/Opportunity/relations/opportunityForAccount"
136
+ "relations/Opportunity/opportunityForAccount"
137
137
  )
138
138
 
139
139
 
@@ -160,14 +160,14 @@ def test_map_leads_converted_links():
160
160
  async def test_retired_structural_alias_is_rejected(ingest):
161
161
  service, _transport = ingest
162
162
  with pytest.raises(IngestError, match="node_type"):
163
- await ingest_entities([{"id": "a", "type": "Account"}], ingest=service)
163
+ await STREAM.entities([{"id": "a", "type": "Account"}], ingest=service)
164
164
 
165
165
 
166
166
  @pytest.mark.asyncio
167
167
  async def test_empty_native_ingest_is_rejected(ingest):
168
168
  service, _transport = ingest
169
169
  with pytest.raises(IngestError, match="at least one entity"):
170
- await ingest_entities([], ingest=service)
170
+ await STREAM.entities([], ingest=service)
171
171
 
172
172
 
173
173
  @pytest.mark.asyncio
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+ import importlib.metadata
2
3
 
3
4
 
4
5
  @pytest.mark.concept("SFDC-1.0")
@@ -7,7 +8,7 @@ def test_startup():
7
8
 
8
9
  import salesforce_agent
9
10
 
10
- assert re.fullmatch(r"\d+\.\d+\.\d+", salesforce_agent.__version__)
11
+ assert re.fullmatch(r"\d+\.\d+\.\d+", importlib.metadata.version("salesforce-agent"))
11
12
 
12
13
 
13
14
  @pytest.mark.concept("SFDC-1.0")
@@ -18,13 +19,3 @@ def test_core_surface_exposed():
18
19
  assert callable(salesforce_agent.SalesforceAuth)
19
20
  assert callable(salesforce_agent.SalesforceConfig)
20
21
  assert callable(salesforce_agent.get_client)
21
-
22
-
23
- @pytest.mark.concept("SFDC-1.0")
24
- def test_mcp_server_entrypoints_importable():
25
- from salesforce_agent.mcp_server import get_mcp_instance, mcp_server
26
-
27
- assert callable(get_mcp_instance)
28
- assert callable(mcp_server)
29
-
30
-
@@ -1,4 +0,0 @@
1
- include LICENSE
2
- include README.md
3
- include requirements.txt
4
- recursive-include salesforce_agent *.py *.json *.md *.yaml *.yml
@@ -1,2 +0,0 @@
1
- agent-connector-sdk[mcp]>=0.3.0,<1.0.0
2
- httpx>=0.27.0
@@ -1,65 +0,0 @@
1
- """CONCEPT:AU-ECO.messaging.native-backend-abstraction Unified ecosystem initialization dynamic check."""
2
-
3
- import importlib
4
- import inspect
5
- from typing import Any
6
-
7
- __version__ = "2.3.2"
8
- __all__: list[str] = []
9
-
10
- CORE_MODULES = [
11
- "salesforce_agent.salesforce_response_models",
12
- "salesforce_agent.salesforce_input_models",
13
- "salesforce_agent.auth",
14
- "salesforce_agent.api_client",
15
- ]
16
- OPTIONAL_MODULES = {
17
- "salesforce_agent.mcp_server": "mcp",
18
- }
19
-
20
-
21
- def _expose_members(module):
22
- for name, obj in inspect.getmembers(module):
23
- if (inspect.isclass(obj) or inspect.isfunction(obj)) and not name.startswith(
24
- "_"
25
- ):
26
- globals()[name] = obj
27
- if name not in __all__:
28
- __all__.append(name)
29
-
30
-
31
- for module_name in CORE_MODULES:
32
- module = importlib.import_module(module_name)
33
- _expose_members(module)
34
-
35
- _loaded_optional_modules: dict[str, Any] = {}
36
-
37
-
38
- def _import_module_safely(module_name: str):
39
- try:
40
- return importlib.import_module(module_name)
41
- except ImportError:
42
- return None
43
-
44
-
45
- def __getattr__(name: str) -> Any:
46
- if name == "_MCP_AVAILABLE":
47
- mcp_key = next((k for k in OPTIONAL_MODULES if "mcp_server" in k), None)
48
- return _import_module_safely(mcp_key) is not None if mcp_key else False
49
-
50
- for module_name in OPTIONAL_MODULES:
51
- if module_name not in _loaded_optional_modules:
52
- module = _import_module_safely(module_name)
53
- if module is not None:
54
- _loaded_optional_modules[module_name] = module
55
- _expose_members(module)
56
-
57
- module = _loaded_optional_modules.get(module_name)
58
- if module is not None and hasattr(module, name):
59
- return getattr(module, name)
60
-
61
- raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
62
-
63
-
64
- def __dir__() -> list[str]:
65
- return sorted(list(globals().keys()) + __all__)
@@ -1,4 +0,0 @@
1
- from salesforce_agent.mcp_server import mcp_server
2
-
3
- if __name__ == "__main__":
4
- mcp_server()
@@ -1,29 +0,0 @@
1
- {
2
- "_comment": "Tier-1 mcp_tool source presets for salesforce-agent (AU-KG.ingest.mcp-tool-connector). Syncs Salesforce CRM objects into the KG as documents via the salesforce-agent MCP server's salesforce_soql tool. Contributed presets win over the central MCP_TOOL_PRESETS. The native typed-node path is salesforce_ingest_crm / salesforce_agent.kg_ingest.",
3
- "salesforce-accounts": {
4
- "server": "salesforce-mcp",
5
- "tool": "salesforce_soql_query",
6
- "params": {
7
- "soql": "SELECT Id, Name, Industry, Type, Website, Description FROM Account"
8
- },
9
- "records_path": "records",
10
- "id_field": "Id",
11
- "title_field": "Name",
12
- "text_field": "Description",
13
- "doc_type": "salesforce_account",
14
- "params_style": "args"
15
- },
16
- "salesforce-opportunities": {
17
- "server": "salesforce-mcp",
18
- "tool": "salesforce_soql_query",
19
- "params": {
20
- "soql": "SELECT Id, Name, StageName, Amount, CloseDate, Description FROM Opportunity"
21
- },
22
- "records_path": "records",
23
- "id_field": "Id",
24
- "title_field": "Name",
25
- "text_field": "Description",
26
- "doc_type": "salesforce_opportunity",
27
- "params_style": "args"
28
- }
29
- }
@@ -1,8 +0,0 @@
1
- {
2
- "algorithm": "agent-connector-sdk:mcp-tool-contract-compat:v2",
3
- "connector": "salesforce-mcp",
4
- "schema_version": "1",
5
- "tools": {
6
- "salesforce_soql_query": "1933ac409fc622368416ff0e4ca41e84d809f7a139709bccb60f5097c5b6b6e9"
7
- }
8
- }
@@ -1,99 +0,0 @@
1
- """Main FastMCP server and tool registration for the Salesforce connector."""
2
-
3
- import sys
4
- from typing import Any
5
-
6
- from agent_connector_sdk.config import load_config
7
- from agent_connector_sdk.mcp.server import create_mcp_server
8
- from agent_connector_sdk.mcp.tool_surface import register_tool_surface
9
- from fastmcp.utilities.logging import get_logger
10
- from starlette.requests import Request
11
- from starlette.responses import JSONResponse
12
-
13
- from salesforce_agent.api import (
14
- AdminClient,
15
- BulkClient,
16
- DescribeClient,
17
- QueryClient,
18
- RecordsClient,
19
- )
20
- from salesforce_agent.auth import get_client
21
- from salesforce_agent.mcp.mcp_salesforce import (
22
- register_admin_tools,
23
- register_bulk_tools,
24
- register_describe_tools,
25
- register_ingest_tools,
26
- register_records_tools,
27
- register_soql_tools,
28
- )
29
-
30
- __version__ = "2.3.2"
31
- logger = get_logger(name="salesforce_agent")
32
-
33
-
34
- def _operation_targets() -> list[dict[str, Any]]:
35
- """One operation-tool group per resource client of the ``Api`` facade."""
36
- resources = {
37
- "soql": QueryClient,
38
- "records": RecordsClient,
39
- "describe": DescribeClient,
40
- "bulk": BulkClient,
41
- "admin": AdminClient,
42
- }
43
- return [
44
- {
45
- "client_cls": client_cls,
46
- "get_client": (lambda name=name: getattr(get_client(), name)),
47
- "prefix": f"salesforce_{name}",
48
- }
49
- for name, client_cls in resources.items()
50
- ]
51
-
52
-
53
- def get_mcp_instance() -> tuple[Any, ...]:
54
- load_config()
55
- args, mcp, middlewares = create_mcp_server(
56
- name="Salesforce MCP",
57
- version=__version__,
58
- instructions=(
59
- "Salesforce MCP Server — SOQL/SOSL queries, record CRUD with "
60
- "composite/collections batching, metadata describe, Bulk API "
61
- "2.0 ingest, and org administration. Destructive operations are "
62
- "gated by SALESFORCE_ALLOW_DESTRUCTIVE."
63
- ),
64
- )
65
-
66
- @mcp.custom_route("/health", methods=["GET"])
67
- async def health_check(request: Request) -> JSONResponse:
68
- return JSONResponse({"status": "OK"})
69
-
70
- register_tool_surface(
71
- mcp,
72
- service="salesforce-agent",
73
- verbose_targets=_operation_targets(),
74
- registrars=[
75
- register_soql_tools,
76
- register_records_tools,
77
- register_describe_tools,
78
- register_bulk_tools,
79
- register_admin_tools,
80
- register_ingest_tools,
81
- ],
82
- )
83
-
84
- for mw in middlewares:
85
- mcp.add_middleware(mw)
86
- return mcp, args, middlewares
87
-
88
-
89
- def mcp_server() -> None:
90
- mcp, args, middlewares = get_mcp_instance()
91
- print(f"Salesforce MCP v{__version__}", file=sys.stderr)
92
- if args.transport == "streamable-http":
93
- mcp.run(transport="streamable-http", host=args.host, port=args.port)
94
- else:
95
- mcp.run(transport="stdio")
96
-
97
-
98
- if __name__ == "__main__":
99
- mcp_server()
@@ -1,17 +0,0 @@
1
- [agent_connector_sdk.connector]
2
- salesforce-mcp = salesforce_agent
3
-
4
- [agent_connector_sdk.ontology_providers]
5
- salesforce-agent = salesforce_agent.ontology
6
-
7
- [agent_connector_sdk.prompt_providers]
8
- salesforce-agent = salesforce_agent.prompts
9
-
10
- [agent_connector_sdk.skill_providers]
11
- salesforce-agent = salesforce_agent.skills
12
-
13
- [agent_connector_sdk.source_connector_providers]
14
- salesforce-agent = salesforce_agent.connectors
15
-
16
- [console_scripts]
17
- salesforce-mcp = salesforce_agent.mcp_server:mcp_server
@@ -1,43 +0,0 @@
1
- """CONN-SALESFORCE-AGENT-CONNECTOR-CONTENT-R001: the server lists its packaged skills, ontology and prompts by default."""
2
-
3
- from __future__ import annotations
4
-
5
- import asyncio
6
- import importlib
7
- from pathlib import Path
8
-
9
- import pytest
10
- from fastmcp import Client
11
-
12
- PACKAGE = "salesforce_agent"
13
- ROOT = Path(list(importlib.import_module(PACKAGE).__path__)[0])
14
-
15
- pytestmark = pytest.mark.spec("CONN-SALESFORCE-AGENT-CONNECTOR-CONTENT-R001")
16
-
17
-
18
- def _server():
19
- namespace = {"__name__": PACKAGE + ".mcp_server"}
20
- exec(
21
- "from agent_connector_sdk.mcp.server import create_mcp_server\n"
22
- "result = create_mcp_server('salesforce-mcp', version='0', command_args=[])",
23
- namespace,
24
- )
25
- return namespace["result"][1]
26
-
27
-
28
- async def _listings():
29
- async with Client(_server()) as client:
30
- resources = {str(r.uri) for r in await client.list_resources()}
31
- prompts = {p.name for p in await client.list_prompts()}
32
- return resources, prompts
33
-
34
-
35
- def test_default_content_surfaces() -> None:
36
- resources, prompts = asyncio.run(_listings())
37
- if list(ROOT.glob("skills/*/SKILL.md")):
38
- assert any(u.startswith("skill://") for u in resources)
39
- if list(ROOT.glob("ontology/*.ttl")):
40
- assert any(u.startswith("ontology://salesforce-mcp/") for u in resources)
41
- for path in ROOT.glob("prompts/*.json"):
42
- if not path.name.startswith("_"):
43
- assert path.stem in prompts
@@ -1,12 +0,0 @@
1
- import pytest
2
-
3
-
4
-
5
-
6
- @pytest.mark.concept("SFDC-1.0")
7
- def test_unknown_attribute_raises():
8
- import salesforce_agent
9
-
10
- missing_attribute = "does_not_exist"
11
- with pytest.raises(AttributeError):
12
- getattr(salesforce_agent, missing_attribute)